From 1d3090326210c6e6f7ec5432799ded25b75bba46 Mon Sep 17 00:00:00 2001 From: Hans Hagen Date: Thu, 28 May 2009 11:23:00 +0200 Subject: beta 2009.05.28 11:23 --- context/data/cont-pe-scite.properties | 97 + context/data/context-bbedit-pe.xml | 1 + context/data/context-jedit-pe.xml | 2 + context/data/context.properties | 30 +- doc/context/bib/bibmod-doc.pdf | Bin 281102 -> 284752 bytes doc/context/bib/bibmod-doc.tex | 8 +- fonts/enc/dvips/context/lm-ec-os.enc | 258 - fonts/enc/dvips/context/lm-qx-os.enc | 258 - fonts/enc/dvips/context/lm-qxtt-os.enc | 258 - fonts/enc/dvips/context/lm-t5-os.enc | 258 - fonts/enc/dvips/context/lm-texnansi-os.enc | 258 - fonts/enc/dvips/context/q-8r.enc | 264 + fonts/map/dvips/context/contnav.map | 1 + fonts/map/dvips/jmn/hans.map | 2 + fonts/map/pdftex/context/cs-qbk.map | 15 - fonts/map/pdftex/context/cs-qcs.map | 15 - fonts/map/pdftex/context/cs-qpl.map | 15 - fonts/map/pdftex/context/cs-qtm.map | 15 - fonts/map/pdftex/context/ec-public-lm.map | 3 - fonts/map/pdftex/context/ec-qbk.map | 15 - fonts/map/pdftex/context/ec-qcs.map | 15 - fonts/map/pdftex/context/ec-qpl.map | 15 - fonts/map/pdftex/context/ec-qtm.map | 15 - fonts/map/pdftex/context/el-public-lm.map | 3 - fonts/map/pdftex/context/el-qbk.map | 15 - fonts/map/pdftex/context/el-qcs.map | 15 - fonts/map/pdftex/context/el-qpl.map | 15 - fonts/map/pdftex/context/el-qtm.map | 15 - fonts/map/pdftex/context/l7x-qbk.map | 15 - fonts/map/pdftex/context/l7x-qcs.map | 15 - fonts/map/pdftex/context/l7x-qpl.map | 15 - fonts/map/pdftex/context/l7x-qtm.map | 15 - fonts/map/pdftex/context/original-youngryu-px.map | 17 +- fonts/map/pdftex/context/original-youngryu-tx.map | 31 +- fonts/map/pdftex/context/qx-public-lm.map | 3 - fonts/map/pdftex/context/qx-qbk.map | 15 - fonts/map/pdftex/context/qx-qcs.map | 15 - fonts/map/pdftex/context/qx-qpl.map | 15 - fonts/map/pdftex/context/qx-qtm.map | 15 - fonts/map/pdftex/context/rm-qbk.map | 15 - fonts/map/pdftex/context/rm-qcs.map | 15 - fonts/map/pdftex/context/rm-qpl.map | 15 - fonts/map/pdftex/context/rm-qtm.map | 15 - fonts/map/pdftex/context/t2a-qbk.map | 11 - fonts/map/pdftex/context/t2a-qcs.map | 11 - fonts/map/pdftex/context/t2a-qpl.map | 11 - fonts/map/pdftex/context/t2a-qtm.map | 11 - fonts/map/pdftex/context/t2b-qbk.map | 11 - fonts/map/pdftex/context/t2b-qcs.map | 11 - fonts/map/pdftex/context/t2b-qpl.map | 11 - fonts/map/pdftex/context/t2b-qtm.map | 11 - fonts/map/pdftex/context/t2c-qbk.map | 11 - fonts/map/pdftex/context/t2c-qcs.map | 11 - fonts/map/pdftex/context/t2c-qpl.map | 11 - fonts/map/pdftex/context/t2c-qtm.map | 11 - fonts/map/pdftex/context/t5-public-lm.map | 3 - fonts/map/pdftex/context/t5-qbk.map | 15 - fonts/map/pdftex/context/t5-qcs.map | 15 - fonts/map/pdftex/context/t5-qpl.map | 15 - fonts/map/pdftex/context/t5-qtm.map | 15 - fonts/map/pdftex/context/texnansi-public-lm.map | 3 - fonts/map/pdftex/context/texnansi-qbk.map | 15 - fonts/map/pdftex/context/texnansi-qcs.map | 15 - fonts/map/pdftex/context/texnansi-qpl.map | 15 - fonts/map/pdftex/context/texnansi-qtm.map | 15 - fonts/map/pdftex/context/ts1-qbk.map | 11 - fonts/map/pdftex/context/ts1-qcs.map | 11 - fonts/map/pdftex/context/ts1-qpl.map | 11 - fonts/map/pdftex/context/ts1-qtm.map | 11 - metapost/context/base/metafun.mp | 2 + metapost/context/base/mp-chem.mp | 729 ++ metapost/context/base/mp-core.mp | 125 +- metapost/context/base/mp-mlib.mp | 90 +- metapost/context/base/mp-page.mp | 2 +- metapost/context/base/mp-text.mp | 3 +- metapost/context/base/mp-tool.mp | 58 +- scripts/context/lua/luatools.lua | 8503 +++++++------- scripts/context/lua/mtx-babel.lua | 18 +- scripts/context/lua/mtx-cache.lua | 4 +- scripts/context/lua/mtx-chars.lua | 306 +- scripts/context/lua/mtx-check.lua | 43 +- scripts/context/lua/mtx-context.lua | 979 +- scripts/context/lua/mtx-convert.lua | 8 +- scripts/context/lua/mtx-fonts.lua | 117 +- scripts/context/lua/mtx-grep.lua | 106 +- scripts/context/lua/mtx-interface.lua | 64 +- scripts/context/lua/mtx-metatex.lua | 69 + scripts/context/lua/mtx-mptopdf.lua | 24 +- scripts/context/lua/mtx-package.lua | 68 + scripts/context/lua/mtx-patterns.lua | 101 +- scripts/context/lua/mtx-profile.lua | 164 + scripts/context/lua/mtx-server-ctx-fonttest.lua | 681 ++ scripts/context/lua/mtx-server-ctx-help.lua | 648 ++ scripts/context/lua/mtx-server-ctx-startup.lua | 53 + scripts/context/lua/mtx-server.lua | 132 +- scripts/context/lua/mtx-timing.lua | 201 + scripts/context/lua/mtx-unzip.lua | 101 + scripts/context/lua/mtx-update.lua | 419 +- scripts/context/lua/mtx-watch.lua | 24 +- scripts/context/lua/mtxrun.lua | 12057 +++++++++++--------- scripts/context/lua/x-ldx.lua | 4 +- scripts/context/ruby/base/exa.rb | 9 +- scripts/context/ruby/base/file.rb | 7 +- scripts/context/ruby/base/kpse.rb | 8 +- scripts/context/ruby/base/state.rb | 4 +- scripts/context/ruby/base/tex.rb | 176 +- scripts/context/ruby/base/texutil.rb | 33 +- scripts/context/ruby/base/tool.rb | 15 +- scripts/context/ruby/ctxtools.rb | 4 +- scripts/context/ruby/fcd_start.rb | 19 +- scripts/context/ruby/graphics/gs.rb | 20 +- scripts/context/ruby/pdftools.rb | 3 +- scripts/context/ruby/rlxtools.rb | 3 +- scripts/context/ruby/rsfiltool.rb | 3 +- scripts/context/ruby/runtools.rb | 3 +- scripts/context/ruby/texexec.rb | 8 +- scripts/context/ruby/texmfstart.rb | 1261 +- scripts/context/ruby/textools.rb | 3 +- scripts/context/ruby/www/admin.rb | 215 - scripts/context/ruby/www/common.rb | 80 - scripts/context/ruby/www/dir.rb | 155 - scripts/context/ruby/www/exa.rb | 387 - scripts/context/ruby/www/lib.rb | 1405 --- scripts/context/ruby/www/login.rb | 13 - scripts/context/ruby/wwwclient.rb | 677 -- scripts/context/ruby/wwwserver.rb | 293 - scripts/context/ruby/wwwwatch.rb | 497 - scripts/context/stubs/mswin/ctxtools.bat | 5 +- scripts/context/stubs/mswin/exatools.bat | 2 - scripts/context/stubs/mswin/luatools.lua | 6977 +++++++++++ scripts/context/stubs/mswin/makempy.bat | 5 +- scripts/context/stubs/mswin/metatex.cmd | 5 + scripts/context/stubs/mswin/mpstools.bat | 5 +- scripts/context/stubs/mswin/mptopdf.bat | 5 +- scripts/context/stubs/mswin/mtxrun.lua | 10190 +++++++++++++++++ scripts/context/stubs/mswin/mtxtools.bat | 5 + scripts/context/stubs/mswin/pdftools.bat | 5 +- scripts/context/stubs/mswin/pdftrimwhite.bat | 2 - scripts/context/stubs/mswin/pstopdf.bat | 5 +- scripts/context/stubs/mswin/rlxtools.bat | 5 +- scripts/context/stubs/mswin/runtools.bat | 5 +- scripts/context/stubs/mswin/texexec.bat | 5 +- scripts/context/stubs/mswin/texexec.cmd | 5 + scripts/context/stubs/mswin/texfind.bat | 2 - scripts/context/stubs/mswin/texfont.bat | 5 +- scripts/context/stubs/mswin/texmfstart.cmd | 5 + scripts/context/stubs/mswin/texshow.bat | 2 - scripts/context/stubs/mswin/textools.bat | 5 +- scripts/context/stubs/mswin/texutil.bat | 5 +- scripts/context/stubs/mswin/tmftools.bat | 5 +- scripts/context/stubs/mswin/xmltools.bat | 5 +- scripts/context/stubs/unix/ctxtools | 2 +- scripts/context/stubs/unix/exatools | 2 - scripts/context/stubs/unix/luatools | 6977 +++++++++++ scripts/context/stubs/unix/makempy | 2 +- scripts/context/stubs/unix/metatex | 2 + scripts/context/stubs/unix/mpstools | 2 +- scripts/context/stubs/unix/mptopdf | 2 +- scripts/context/stubs/unix/mtxrun | 10190 +++++++++++++++++ scripts/context/stubs/unix/mtxtools | 2 + scripts/context/stubs/unix/pdftools | 2 +- scripts/context/stubs/unix/pdftrimwhite | 2 - scripts/context/stubs/unix/pstopdf | 2 +- scripts/context/stubs/unix/rlxtools | 2 +- scripts/context/stubs/unix/runtools | 2 +- scripts/context/stubs/unix/texexec | 2 +- scripts/context/stubs/unix/texfind | 2 - scripts/context/stubs/unix/texfont | 2 +- scripts/context/stubs/unix/texmfstart | 2 + scripts/context/stubs/unix/texshow | 2 - scripts/context/stubs/unix/textools | 2 +- scripts/context/stubs/unix/texutil | 2 +- scripts/context/stubs/unix/tmftools | 2 +- scripts/context/stubs/unix/xmltools | 2 +- tex/context/base/attr-ini.lua | 853 +- tex/context/base/attr-ini.tex | 163 +- tex/context/base/back-ini.lua | 75 + tex/context/base/back-ini.tex | 896 ++ tex/context/base/back-pdf.lua | 189 + tex/context/base/back-pdf.tex | 3226 ++++++ tex/context/base/bibl-bib.lua | 233 + tex/context/base/bibl-bib.tex | 29 + tex/context/base/bibl-tst.lua | 21 + tex/context/base/catc-act.tex | 61 + tex/context/base/catc-ctx.tex | 207 + tex/context/base/catc-def.tex | 142 + tex/context/base/catc-ini.lua | 28 + tex/context/base/catc-ini.mkii | 229 + tex/context/base/catc-ini.mkiv | 255 + tex/context/base/catc-sym.tex | 118 + tex/context/base/char-cmp.lua | 2 + tex/context/base/char-def.lua | 1248 +- tex/context/base/char-enc.lua | 163 + tex/context/base/char-enc.tex | 18 + tex/context/base/char-ini.lua | 619 +- tex/context/base/char-ini.tex | 40 +- tex/context/base/char-map.lua | 19 +- tex/context/base/char-syn.lua | 140 - tex/context/base/char-utf.lua | 146 +- tex/context/base/char-utf.tex | 26 +- tex/context/base/chem-ini.lua | 74 + tex/context/base/chem-ini.mkiv | 42 + tex/context/base/chem-str-test.tex | 560 + tex/context/base/chem-str.lua | 488 + tex/context/base/chem-str.mkiv | 526 + tex/context/base/colo-ext.mkii | 57 + tex/context/base/colo-ext.mkiv | 57 + tex/context/base/colo-ext.tex | 57 - tex/context/base/colo-hex.mkii | 115 + tex/context/base/colo-hex.mkiv | 115 + tex/context/base/colo-hex.tex | 120 +- tex/context/base/colo-ini.lua | 181 +- tex/context/base/colo-ini.mkii | 922 +- tex/context/base/colo-ini.mkiv | 983 +- tex/context/base/colo-ini.tex | 1051 -- tex/context/base/colo-run.tex | 3 +- tex/context/base/cont-cs.tex | 10 +- tex/context/base/cont-de.tex | 10 +- tex/context/base/cont-en.tex | 8 +- tex/context/base/cont-fil.tex | 2 +- tex/context/base/cont-fr.tex | 10 +- tex/context/base/cont-gb.tex | 10 +- tex/context/base/cont-it.tex | 10 +- tex/context/base/cont-log.tex | 71 +- tex/context/base/cont-new.mkiv | 88 +- tex/context/base/cont-new.tex | 100 +- tex/context/base/cont-nl.tex | 10 +- tex/context/base/cont-old.tex | 2 +- tex/context/base/cont-pe.tex | 10 +- tex/context/base/cont-ro.tex | 10 +- tex/context/base/cont-sys.ori | 9 +- tex/context/base/cont-usr.ori | 2 +- tex/context/base/context-base.lmx | 38 + tex/context/base/context-characters.lmx | 66 +- tex/context/base/context-debug.lmx | 66 +- tex/context/base/context-error.lmx | 46 +- tex/context/base/context-fonttest.lmx | 47 + tex/context/base/context-help.lmx | 88 + tex/context/base/context-timing.lmx | 52 + tex/context/base/context.css | 15 + tex/context/base/context.mkii | 198 +- tex/context/base/context.mkiv | 422 +- tex/context/base/context.rme | 85 + tex/context/base/context.tex | 15 +- tex/context/base/core-bar.tex | 2 +- tex/context/base/core-blk.lua | 145 - tex/context/base/core-blk.mkiv | 109 - tex/context/base/core-blk.tex | 130 +- tex/context/base/core-box.tex | 3 +- tex/context/base/core-buf.lua | 194 +- tex/context/base/core-buf.mkii | 326 +- tex/context/base/core-buf.mkiv | 308 +- tex/context/base/core-buf.tex | 250 - tex/context/base/core-con.lua | 281 +- tex/context/base/core-con.mkii | 775 +- tex/context/base/core-con.mkiv | 831 +- tex/context/base/core-con.tex | 744 -- tex/context/base/core-ctx.lua | 41 +- tex/context/base/core-ctx.mkii | 2 +- tex/context/base/core-ctx.mkiv | 3 +- tex/context/base/core-ctx.tex | 22 - tex/context/base/core-dat.tex | 66 +- tex/context/base/core-def.mkii | 77 + tex/context/base/core-def.mkiv | 74 + tex/context/base/core-def.tex | 27 - tex/context/base/core-des.tex | 7 +- tex/context/base/core-env.mkii | 543 + tex/context/base/core-env.mkiv | 472 + tex/context/base/core-fig.tex | 4 +- tex/context/base/core-fil.tex | 56 +- tex/context/base/core-fld.mkii | 1080 ++ tex/context/base/core-fld.mkiv | 1079 ++ tex/context/base/core-fld.tex | 1080 -- tex/context/base/core-fnt.mkii | 726 ++ tex/context/base/core-fnt.mkiv | 498 + tex/context/base/core-fnt.tex | 726 -- tex/context/base/core-gen.tex | 137 +- tex/context/base/core-grd.tex | 2 +- tex/context/base/core-inc.lua | 608 +- tex/context/base/core-inc.mkii | 95 +- tex/context/base/core-inc.mkiv | 12 +- tex/context/base/core-inc.tex | 18 - tex/context/base/core-ini.tex | 2 +- tex/context/base/core-ins.tex | 42 +- tex/context/base/core-int.mkii | 2217 ++++ tex/context/base/core-int.mkiv | 2036 ++++ tex/context/base/core-int.tex | 2355 ---- tex/context/base/core-itm.tex | 36 +- tex/context/base/core-job.lua | 154 +- tex/context/base/core-job.mkii | 316 +- tex/context/base/core-job.mkiv | 333 +- tex/context/base/core-job.tex | 368 - tex/context/base/core-lme.tex | 2 +- tex/context/base/core-lnt.tex | 2 +- tex/context/base/core-lst.tex | 3 +- tex/context/base/core-ltb.tex | 856 -- tex/context/base/core-mak.tex | 2 +- tex/context/base/core-mar.tex | 5 +- tex/context/base/core-mat.tex | 60 +- tex/context/base/core-mis.mkii | 2676 +++++ tex/context/base/core-mis.mkiv | 2606 +++++ tex/context/base/core-mis.tex | 2733 ----- tex/context/base/core-nav.mkii | 379 + tex/context/base/core-nav.mkiv | 425 + tex/context/base/core-nav.tex | 379 - tex/context/base/core-new.tex | 304 - tex/context/base/core-not.tex | 8 +- tex/context/base/core-ntb.tex | 1573 --- tex/context/base/core-num.tex | 2 +- tex/context/base/core-obj.lua | 7 +- tex/context/base/core-obj.mkii | 309 +- tex/context/base/core-obj.mkiv | 220 +- tex/context/base/core-obj.tex | 365 - tex/context/base/core-par.tex | 2 +- tex/context/base/core-pgr.tex | 12 +- tex/context/base/core-pos.lua | 4 +- tex/context/base/core-pos.mkii | 759 +- tex/context/base/core-pos.mkiv | 789 +- tex/context/base/core-pos.tex | 767 -- tex/context/base/core-ref.lua | 106 - tex/context/base/core-ref.mkii | 90 - tex/context/base/core-ref.mkiv | 107 - tex/context/base/core-ref.tex | 261 +- tex/context/base/core-reg.lua | 186 - tex/context/base/core-reg.mkii | 33 - tex/context/base/core-reg.mkiv | 40 - tex/context/base/core-reg.tex | 55 +- tex/context/base/core-rul.lua | 1 - tex/context/base/core-rul.mkii | 3562 ++++++ tex/context/base/core-rul.mkiv | 3635 +++++- tex/context/base/core-rul.tex | 3590 ------ tex/context/base/core-sec.mkii | 2620 ----- tex/context/base/core-sec.mkiv | 2621 ----- tex/context/base/core-sec.tex | 2572 +++++ tex/context/base/core-snc.tex | 4 +- tex/context/base/core-spa.lua | 1979 +--- tex/context/base/core-spa.mkii | 4648 +++++++- tex/context/base/core-spa.mkiv | 4176 ++++++- tex/context/base/core-spa.tex | 4637 -------- tex/context/base/core-stg.tex | 4 +- tex/context/base/core-syn.lua | 127 - tex/context/base/core-syn.mkii | 28 - tex/context/base/core-syn.mkiv | 34 - tex/context/base/core-syn.tex | 42 +- tex/context/base/core-sys.mkii | 384 +- tex/context/base/core-sys.mkiv | 373 +- tex/context/base/core-sys.tex | 401 - tex/context/base/core-tab.tex | 2499 ---- tex/context/base/core-tbl.tex | 1436 --- tex/context/base/core-trf.tex | 28 +- tex/context/base/core-tsp.tex | 427 - tex/context/base/core-two.lua | 20 +- tex/context/base/core-two.mkii | 65 +- tex/context/base/core-two.mkiv | 77 +- tex/context/base/core-two.tex | 103 - tex/context/base/core-uti.lua | 253 +- tex/context/base/core-uti.mkii | 305 +- tex/context/base/core-uti.mkiv | 95 +- tex/context/base/core-uti.tex | 382 - tex/context/base/core-var.tex | 568 +- tex/context/base/core-ver.mkii | 1124 +- tex/context/base/core-ver.mkiv | 1084 +- tex/context/base/core-ver.tex | 1120 -- tex/context/base/core-vis.tex | 32 +- tex/context/base/data-aux.lua | 57 + tex/context/base/data-bin.lua | 26 + tex/context/base/data-con.lua | 122 + tex/context/base/data-crl.lua | 58 + tex/context/base/data-ctx.lua | 29 + tex/context/base/data-gen.lua | 9 + tex/context/base/data-inp.lua | 15 + tex/context/base/data-kps.lua | 101 + tex/context/base/data-lst.lua | 58 + tex/context/base/data-lua.lua | 55 + tex/context/base/data-out.lua | 10 + tex/context/base/data-pre.lua | 90 + tex/context/base/data-res.lua | 2029 ++++ tex/context/base/data-tex.lua | 220 + tex/context/base/data-tmf.lua | 72 + tex/context/base/data-tmp.lua | 174 + tex/context/base/data-tre.lua | 43 + tex/context/base/data-use.lua | 127 + tex/context/base/data-zip.lua | 241 + tex/context/base/enco-cyr.tex | 2 + tex/context/base/enco-def.tex | 6 +- tex/context/base/enco-fpl.tex | 2 +- tex/context/base/enco-ini.mkii | 1125 +- tex/context/base/enco-ini.mkiv | 583 +- tex/context/base/enco-ini.tex | 1228 -- tex/context/base/enco-mis.tex | 37 - tex/context/base/enco-pfr.mkii | 20 - tex/context/base/enco-pfr.mkiv | 22 - tex/context/base/enco-pfr.tex | 18 +- tex/context/base/enco-run.tex | 52 +- tex/context/base/enco-t5.tex | 4 +- tex/context/base/enco-utf.tex | 3126 ----- tex/context/base/enco-x5.tex | 34 +- tex/context/base/filt-ini.tex | 62 +- tex/context/base/font-afm.lua | 344 +- tex/context/base/font-bfm.tex | 2 +- tex/context/base/font-chi.tex | 2 +- tex/context/base/font-chk.lua | 80 + tex/context/base/font-cid.lua | 143 + tex/context/base/font-col.lua | 98 +- tex/context/base/font-col.mkiv | 146 + tex/context/base/font-col.tex | 148 - tex/context/base/font-ctx.lua | 387 + tex/context/base/font-def.lua | 624 +- tex/context/base/font-dum.lua | 113 + tex/context/base/font-enc.lua | 16 +- tex/context/base/font-ext.lua | 304 +- tex/context/base/font-fbk.lua | 102 +- tex/context/base/font-ini.lua | 53 +- tex/context/base/font-ini.mkii | 671 +- tex/context/base/font-ini.mkiv | 2515 ++-- tex/context/base/font-jap.tex | 2 +- tex/context/base/font-log.lua | 53 + tex/context/base/font-map.lua | 32 +- tex/context/base/font-mis.lua | 91 + tex/context/base/font-ota.lua | 320 + tex/context/base/font-otb.lua | 364 + tex/context/base/font-otc.lua | 238 + tex/context/base/font-otd.lua | 78 + tex/context/base/font-otf.lua | 5983 ++-------- tex/context/base/font-oti.lua | 57 + tex/context/base/font-otn.lua | 2496 ++++ tex/context/base/font-otp.lua | 420 + tex/context/base/font-ott.lua | 935 ++ tex/context/base/font-pat.lua | 53 +- tex/context/base/font-run.tex | 3 +- tex/context/base/font-syn.lua | 417 +- tex/context/base/font-tfm.lua | 977 +- tex/context/base/font-tra.mkiv | 113 + tex/context/base/font-uni.mkii | 444 + tex/context/base/font-uni.mkiv | 26 + tex/context/base/font-uni.tex | 465 - tex/context/base/font-unk.mkii | 187 + tex/context/base/font-unk.mkiv | 162 + tex/context/base/font-unk.tex | 185 - tex/context/base/font-vf.lua | 72 +- tex/context/base/font-xtx.lua | 115 + tex/context/base/font-xtx.tex | 357 + tex/context/base/hand-ini.mkii | 91 +- tex/context/base/hand-ini.mkiv | 2 +- tex/context/base/hand-ini.tex | 18 - tex/context/base/java-ini.mkii | 713 ++ tex/context/base/java-ini.mkiv | 688 ++ tex/context/base/java-ini.tex | 742 -- tex/context/base/l-aux.lua | 128 +- tex/context/base/l-boolean.lua | 17 +- tex/context/base/l-dimen.lua | 13 +- tex/context/base/l-dir.lua | 447 +- tex/context/base/l-file.lua | 142 +- tex/context/base/l-io.lua | 211 +- tex/context/base/l-lpeg.lua | 58 +- tex/context/base/l-math.lua | 30 +- tex/context/base/l-md5.lua | 78 +- tex/context/base/l-number.lua | 27 +- tex/context/base/l-os.lua | 88 +- tex/context/base/l-set.lua | 87 +- tex/context/base/l-string.lua | 270 +- tex/context/base/l-table.lua | 328 +- tex/context/base/l-unicode.lua | 79 +- tex/context/base/l-url.lua | 54 +- tex/context/base/l-utils.lua | 62 +- tex/context/base/l-xml.lua | 134 +- tex/context/base/lang-alt.tex | 5 +- tex/context/base/lang-ana.tex | 6 +- tex/context/base/lang-ara.tex | 5 +- tex/context/base/lang-art.tex | 6 +- tex/context/base/lang-bal.tex | 6 +- tex/context/base/lang-cel.tex | 6 +- tex/context/base/lang-chi.tex | 6 +- tex/context/base/lang-cjk.tex | 328 + tex/context/base/lang-ctx.tex | 37 +- tex/context/base/lang-cyr.tex | 14 +- tex/context/base/lang-dis.tex | 8 +- tex/context/base/lang-frq.tex | 4 +- tex/context/base/lang-ger.tex | 44 +- tex/context/base/lang-grk.tex | 9 +- tex/context/base/lang-ind.tex | 2 +- tex/context/base/lang-ini.lua | 131 +- tex/context/base/lang-ini.mkii | 588 +- tex/context/base/lang-ini.mkiv | 565 +- tex/context/base/lang-ini.tex | 692 -- tex/context/base/lang-ita.tex | 57 +- tex/context/base/lang-jap.tex | 5 +- tex/context/base/lang-lab.mkii | 295 + tex/context/base/lang-lab.mkiv | 266 + tex/context/base/lang-lab.tex | 284 - tex/context/base/lang-mis.tex | 6 +- tex/context/base/lang-sla.tex | 23 +- tex/context/base/lang-spa.tex | 2 +- tex/context/base/lang-spe.mkii | 244 + tex/context/base/lang-spe.mkiv | 111 + tex/context/base/lang-spe.tex | 242 - tex/context/base/lang-ura.tex | 6 +- tex/context/base/lang-url.lua | 10 +- tex/context/base/lang-url.mkii | 74 + tex/context/base/lang-url.mkiv | 50 +- tex/context/base/lang-url.tex | 70 - tex/context/base/lang-vn.tex | 5 +- tex/context/base/luat-bas.tex | 64 + tex/context/base/luat-cbk.lua | 13 +- tex/context/base/luat-cnf.lua | 114 + tex/context/base/luat-cod.tex | 161 + tex/context/base/luat-crl.lua | 53 - tex/context/base/luat-deb.lua | 154 - tex/context/base/luat-deb.tex | 49 - tex/context/base/luat-dum.lua | 60 + tex/context/base/luat-env.lua | 304 +- tex/context/base/luat-env.tex | 172 - tex/context/base/luat-exe.lua | 13 +- tex/context/base/luat-fio.lua | 81 + tex/context/base/luat-ini.lua | 129 +- tex/context/base/luat-ini.tex | 222 +- tex/context/base/luat-inp.lua | 2300 ---- tex/context/base/luat-iop.lua | 18 +- tex/context/base/luat-kps.lua | 102 - tex/context/base/luat-lib.lua | 174 - tex/context/base/luat-lib.tex | 86 +- tex/context/base/luat-lmx.lua | 141 - tex/context/base/luat-lmx.tex | 16 - tex/context/base/luat-log.lua | 155 - tex/context/base/luat-lua.lua | 2 +- tex/context/base/luat-run.lua | 69 + tex/context/base/luat-soc.lua | 11 + tex/context/base/luat-sta.lua | 44 +- tex/context/base/luat-sto.lua | 134 + tex/context/base/luat-tex.lua | 588 - tex/context/base/luat-tmp.lua | 433 - tex/context/base/luat-tra.lua | 145 - tex/context/base/luat-tre.lua | 45 - tex/context/base/luat-uni.lua | 21 - tex/context/base/luat-uni.tex | 33 - tex/context/base/luat-zip.lua | 249 - tex/context/base/lxml-ent.lua | 115 + tex/context/base/lxml-ini.lua | 588 +- tex/context/base/lxml-ini.tex | 71 +- tex/context/base/lxml-mis.lua | 106 + tex/context/base/lxml-pth.lua | 1555 +++ tex/context/base/lxml-tab.lua | 783 ++ tex/context/base/m-arabtex.tex | 2 +- tex/context/base/m-chemic.mkii | 21 + tex/context/base/m-chemic.mkiv | 19 + tex/context/base/m-chemic.tex | 10 +- tex/context/base/m-database.tex | 2 +- tex/context/base/m-educat.tex | 33 - tex/context/base/m-gamma.tex | 230 - tex/context/base/m-mkii.mkiv | 21 + tex/context/base/m-newmat.tex | 14 +- tex/context/base/m-pictex.tex | 11 +- tex/context/base/m-subsub.tex | 47 - tex/context/base/m-timing.tex | 197 +- tex/context/base/m-track.tex | 5 + tex/context/base/m-translate.tex | 6 +- tex/context/base/m-visual.tex | 1 - tex/context/base/math-ali.mkiv | 1059 ++ tex/context/base/math-ams.tex | 4 +- tex/context/base/math-arr.mkii | 391 + tex/context/base/math-arr.mkiv | 439 + tex/context/base/math-def.mkiv | 338 + tex/context/base/math-del.mkiv | 63 + tex/context/base/math-dim.lua | 310 + tex/context/base/math-dis.mkiv | 20 + tex/context/base/math-ext.lua | 143 + tex/context/base/math-ext.tex | 437 - tex/context/base/math-for.mkiv | 73 + tex/context/base/math-frc.mkii | 66 + tex/context/base/math-frc.mkiv | 209 + tex/context/base/math-ini.lua | 637 +- tex/context/base/math-ini.mkii | 679 +- tex/context/base/math-ini.mkiv | 544 +- tex/context/base/math-ini.tex | 688 -- tex/context/base/math-inl.mkiv | 357 + tex/context/base/math-int.mkiv | 87 + tex/context/base/math-lbr.tex | 8 +- tex/context/base/math-map.lua | 365 + tex/context/base/math-mis.tex | 49 - tex/context/base/math-noa.lua | 336 + tex/context/base/math-pln.mkii | 360 + tex/context/base/math-pln.mkiv | 298 + tex/context/base/math-pln.tex | 355 - tex/context/base/math-run.mkii | 97 + tex/context/base/math-run.tex | 95 - tex/context/base/math-scr.mkiv | 215 + tex/context/base/math-tex.tex | 23 +- tex/context/base/math-tim.tex | 106 +- tex/context/base/math-vfu.lua | 1534 +++ tex/context/base/meta-ini.mkii | 91 +- tex/context/base/meta-ini.mkiv | 431 +- tex/context/base/meta-pdf.lua | 737 +- tex/context/base/meta-pdf.mkii | 936 +- tex/context/base/meta-pdf.mkiv | 833 +- tex/context/base/meta-pdf.tex | 1020 -- tex/context/base/meta-pdh.lua | 630 + tex/context/base/meta-tex.mkii | 2 +- tex/context/base/metatex.tex | 145 + tex/context/base/mlib-ctx.lua | 16 +- tex/context/base/mlib-pdf.lua | 209 +- tex/context/base/mlib-pdf.tex | 6 +- tex/context/base/mlib-pps.lua | 177 +- tex/context/base/mlib-pps.tex | 16 +- tex/context/base/mlib-run.lua | 161 +- tex/context/base/mtx-context-arrange.tex | 105 + tex/context/base/mtx-context-combine.tex | 146 + tex/context/base/mtx-context-ideas.tex | 54 + tex/context/base/mtx-context-listing.tex | 76 + tex/context/base/mtx-context-timing.tex | 46 + tex/context/base/mult-chk.lua | 66 + tex/context/base/mult-chk.mkii | 26 + tex/context/base/mult-chk.mkiv | 103 + tex/context/base/mult-de.tex | 57 + tex/context/base/mult-def.lua | 270 +- tex/context/base/mult-def.tex | 10 +- tex/context/base/mult-en.tex | 57 + tex/context/base/mult-fr.tex | 57 + tex/context/base/mult-his.tex | 19 +- tex/context/base/mult-ini.lua | 31 +- tex/context/base/mult-ini.mkii | 15 +- tex/context/base/mult-ini.mkiv | 34 +- tex/context/base/mult-it.tex | 57 + tex/context/base/mult-mcs.tex | 198 + tex/context/base/mult-mde.tex | 198 + tex/context/base/mult-men.tex | 198 + tex/context/base/mult-mes.lua | 2005 ++++ tex/context/base/mult-mfr.tex | 198 + tex/context/base/mult-mit.tex | 198 + tex/context/base/mult-mnl.tex | 198 + tex/context/base/mult-mno.tex | 198 + tex/context/base/mult-mpe.tex | 198 + tex/context/base/mult-mro.tex | 198 + tex/context/base/mult-nl.tex | 57 + tex/context/base/mult-ro.tex | 57 + tex/context/base/mult-sys.tex | 116 +- tex/context/base/node-dum.lua | 24 + tex/context/base/node-ext.lua | 30 + tex/context/base/node-fin.lua | 363 + tex/context/base/node-fin.tex | 78 + tex/context/base/node-fnt.lua | 206 + tex/context/base/node-ini.lua | 1254 +- tex/context/base/node-ini.tex | 59 +- tex/context/base/node-inj.lua | 608 + tex/context/base/node-par.lua | 2 +- tex/context/base/node-par.tex | 6 +- tex/context/base/node-pro.lua | 155 + tex/context/base/node-res.lua | 110 + tex/context/base/node-seq.lua | 47 +- tex/context/base/node-ser.lua | 274 + tex/context/base/node-shp.lua | 66 + tex/context/base/node-tex.lua | 54 + tex/context/base/node-tra.lua | 399 + tex/context/base/node-tsk.lua | 113 + tex/context/base/node-tst.lua | 108 + tex/context/base/norm-alo.tex | 36 + tex/context/base/norm-ctx.tex | 16 + tex/context/base/norm-etx.tex | 79 + tex/context/base/norm-ltx.tex | 177 + tex/context/base/norm-ptx.tex | 130 + tex/context/base/norm-tex.tex | 351 + tex/context/base/norm-xtx.tex | 18 + tex/context/base/page-app.tex | 4 +- tex/context/base/page-bck.mkii | 593 + tex/context/base/page-bck.mkiv | 521 + tex/context/base/page-bck.tex | 615 - tex/context/base/page-flt.tex | 460 +- tex/context/base/page-flw.tex | 4 +- tex/context/base/page-imp.tex | 29 +- tex/context/base/page-ini.mkii | 1555 +++ tex/context/base/page-ini.mkiv | 1549 +++ tex/context/base/page-ini.tex | 2034 ---- tex/context/base/page-lay.tex | 5 +- tex/context/base/page-lin.lua | 299 +- tex/context/base/page-lin.mkii | 2 +- tex/context/base/page-lin.mkiv | 16 +- tex/context/base/page-log.tex | 34 +- tex/context/base/page-lyr.tex | 8 +- tex/context/base/page-mak.tex | 9 +- tex/context/base/page-mar.tex | 10 +- tex/context/base/page-mis.tex | 268 + tex/context/base/page-mul.tex | 8 +- tex/context/base/page-not.tex | 2 +- tex/context/base/page-num.tex | 15 +- tex/context/base/page-one.mkii | 659 ++ tex/context/base/page-one.mkiv | 662 ++ tex/context/base/page-one.tex | 659 -- tex/context/base/page-par.tex | 4 +- tex/context/base/page-plg.tex | 4 +- tex/context/base/page-run.tex | 2 +- tex/context/base/page-set.tex | 24 +- tex/context/base/page-sid.tex | 4 +- tex/context/base/page-spr.tex | 2 +- tex/context/base/page-str.tex | 6 +- tex/context/base/page-txt.mkii | 784 ++ tex/context/base/page-txt.mkiv | 808 ++ tex/context/base/page-txt.tex | 784 -- tex/context/base/ppchtex.mkii | 3457 ++++++ tex/context/base/ppchtex.mkiv | 3359 ++++++ tex/context/base/ppchtex.tex | 3438 ------ tex/context/base/prop-ini.mkii | 150 + tex/context/base/prop-ini.mkiv | 150 + tex/context/base/prop-ini.tex | 151 - tex/context/base/prop-lay.mkii | 99 + tex/context/base/prop-lay.mkiv | 109 +- tex/context/base/prop-lay.tex | 105 - tex/context/base/prop-mis.mkii | 34 + tex/context/base/prop-mis.mkiv | 34 + tex/context/base/prop-mis.tex | 53 - tex/context/base/prop-run.tex | 39 - tex/context/base/regi-ini.lua | 88 +- tex/context/base/regi-ini.mkii | 167 +- tex/context/base/regi-ini.mkiv | 54 +- tex/context/base/regi-ini.tex | 182 - tex/context/base/regi-syn.tex | 2 +- tex/context/base/regi-utf.tex | 12 +- tex/context/base/s-fnt-01.tex | 4 +- tex/context/base/s-fnt-10.tex | 100 +- tex/context/base/s-fnt-11.tex | 61 + tex/context/base/s-fnt-20.tex | 140 + tex/context/base/s-fnt-21.tex | 46 + tex/context/base/s-fnt-23.tex | 272 + tex/context/base/s-fnt-24.tex | 83 + tex/context/base/s-fnt-25.tex | 162 + tex/context/base/s-fnt-30.tex | 42 + tex/context/base/s-pre-60.tex | 46 +- tex/context/base/s-pre-61.tex | 14 +- tex/context/base/s-pre-62.tex | 20 +- tex/context/base/s-pre-66.tex | 133 + tex/context/base/s-pre-71.tex | 8 +- tex/context/base/s-reg-01.tex | 50 + tex/context/base/scrp-cjk.lua | 576 + tex/context/base/scrp-ini.lua | 386 + tex/context/base/scrp-ini.tex | 91 + tex/context/base/sort-def.mkii | 450 - tex/context/base/sort-def.mkiv | 16 - tex/context/base/sort-def.tex | 432 +- tex/context/base/sort-ini.lua | 135 +- tex/context/base/sort-ini.mkii | 16 +- tex/context/base/sort-ini.mkiv | 8 +- tex/context/base/sort-ini.tex | 32 - tex/context/base/sort-lan.lua | 19 +- tex/context/base/sort-lan.mkii | 203 - tex/context/base/sort-lan.mkiv | 16 - tex/context/base/sort-lan.tex | 189 +- tex/context/base/spec-def.mkii | 20 - tex/context/base/spec-def.mkiv | 23 - tex/context/base/spec-def.tex | 8 +- tex/context/base/spec-dpx.tex | 4 +- tex/context/base/spec-fdf.mkii | 146 - tex/context/base/spec-fdf.mkiv | 31 - tex/context/base/spec-fdf.tex | 205 +- tex/context/base/spec-ini.tex | 154 +- tex/context/base/spec-mis.tex | 26 +- tex/context/base/spec-pdf.lua | 67 - tex/context/base/spec-tpd.mkii | 18 - tex/context/base/spec-tpd.mkiv | 37 - tex/context/base/spec-tpd.tex | 40 +- tex/context/base/spec-var.tex | 2 +- tex/context/base/strc-bkm.lua | 133 + tex/context/base/strc-bkm.tex | 90 + tex/context/base/strc-blk.lua | 145 + tex/context/base/strc-blk.tex | 110 + tex/context/base/strc-def.tex | 302 + tex/context/base/strc-des.lua | 9 + tex/context/base/strc-des.tex | 1018 ++ tex/context/base/strc-doc.lua | 569 + tex/context/base/strc-doc.tex | 166 + tex/context/base/strc-flt.lua | 9 + tex/context/base/strc-flt.tex | 2173 ++++ tex/context/base/strc-ini.lua | 276 + tex/context/base/strc-ini.tex | 88 + tex/context/base/strc-itm.lua | 24 + tex/context/base/strc-itm.tex | 1195 ++ tex/context/base/strc-lst.lua | 392 + tex/context/base/strc-lst.tex | 944 ++ tex/context/base/strc-mar.lua | 18 + tex/context/base/strc-mar.tex | 493 + tex/context/base/strc-mat.lua | 51 + tex/context/base/strc-mat.tex | 933 ++ tex/context/base/strc-not.lua | 248 + tex/context/base/strc-not.tex | 1154 ++ tex/context/base/strc-num.lua | 457 + tex/context/base/strc-num.tex | 440 + tex/context/base/strc-pag.lua | 206 + tex/context/base/strc-pag.tex | 506 + tex/context/base/strc-prc.lua | 9 + tex/context/base/strc-prc.tex | 84 + tex/context/base/strc-ref.lua | 875 ++ tex/context/base/strc-ref.tex | 1905 ++++ tex/context/base/strc-reg.lua | 578 + tex/context/base/strc-reg.tex | 907 ++ tex/context/base/strc-ren.tex | 467 + tex/context/base/strc-sbe.tex | 137 + tex/context/base/strc-sec.tex | 667 ++ tex/context/base/strc-syn.lua | 185 + tex/context/base/strc-syn.tex | 392 + tex/context/base/strc-xml.tex | 87 + tex/context/base/supp-box.tex | 357 +- tex/context/base/supp-dir.mkii | 41 + tex/context/base/supp-dir.mkiv | 21 + tex/context/base/supp-dir.tex | 70 - tex/context/base/supp-eps.tex | 2 +- tex/context/base/supp-fil.lua | 49 +- tex/context/base/supp-fil.mkii | 621 +- tex/context/base/supp-fil.mkiv | 616 +- tex/context/base/supp-fil.tex | 655 -- tex/context/base/supp-fun.tex | 10 +- tex/context/base/supp-ini.tex | 18 - tex/context/base/supp-lan.tex | 4 +- tex/context/base/supp-mat.tex | 13 +- tex/context/base/supp-mis.tex | 3 +- tex/context/base/supp-mpe.tex | 2 +- tex/context/base/supp-mps.tex | 24 +- tex/context/base/supp-mrk.tex | 27 +- tex/context/base/supp-num.tex | 31 +- tex/context/base/supp-pat.tex | 6 +- tex/context/base/supp-pdf.tex | 2 +- tex/context/base/supp-ran.lua | 46 + tex/context/base/supp-ran.mkii | 122 + tex/context/base/supp-ran.mkiv | 30 + tex/context/base/supp-ran.tex | 158 - tex/context/base/supp-spe.tex | 94 +- tex/context/base/supp-tpi.tex | 6 +- tex/context/base/supp-vis.tex | 48 +- tex/context/base/symb-ini.tex | 42 +- tex/context/base/symb-jmn.tex | 1 - tex/context/base/symb-mis.tex | 7 +- tex/context/base/syst-aux.tex | 6841 +++++++++++ tex/context/base/syst-cat.mkii | 61 - tex/context/base/syst-cat.mkiv | 124 - tex/context/base/syst-cat.tex | 517 - tex/context/base/syst-chr.tex | 131 - tex/context/base/syst-con.lua | 28 +- tex/context/base/syst-con.mkii | 109 +- tex/context/base/syst-con.mkiv | 132 +- tex/context/base/syst-con.tex | 144 - tex/context/base/syst-etx.tex | 298 - tex/context/base/syst-ext.tex | 165 +- tex/context/base/syst-fnt.mkii | 46 + tex/context/base/syst-fnt.mkiv | 46 + tex/context/base/syst-fnt.tex | 43 - tex/context/base/syst-gen.tex | 358 +- tex/context/base/syst-ini.tex | 879 ++ tex/context/base/syst-lua.lua | 91 + tex/context/base/syst-lua.tex | 37 + tex/context/base/syst-mtx.tex | 80 - tex/context/base/syst-new.tex | 21 +- tex/context/base/syst-omg.tex | 79 - tex/context/base/syst-pdt.tex | 50 - tex/context/base/syst-pln.tex | 510 +- tex/context/base/syst-prm.tex | 227 - tex/context/base/syst-rtp.tex | 22 - tex/context/base/syst-str.mkii | 7 +- tex/context/base/syst-str.mkiv | 9 + tex/context/base/syst-str.tex | 40 - tex/context/base/syst-var.tex | 18 - tex/context/base/syst-xtx.tex | 36 - tex/context/base/tabl-ltb.tex | 856 ++ tex/context/base/tabl-ntb.mkii | 1584 +++ tex/context/base/tabl-ntb.mkiv | 1571 +++ tex/context/base/tabl-nte.tex | 107 + tex/context/base/tabl-pln.tex | 91 + tex/context/base/tabl-tab.tex | 2507 ++++ tex/context/base/tabl-tbl.tex | 1435 +++ tex/context/base/tabl-tsp.tex | 427 + tex/context/base/task-ini.lua | 45 + tex/context/base/task-ini.tex | 22 + tex/context/base/thrd-ran.tex | 4 +- tex/context/base/thrd-tab.tex | 50 +- tex/context/base/thrd-trg.tex | 9 +- tex/context/base/toks-ini.lua | 43 +- tex/context/base/toks-ini.tex | 6 +- tex/context/base/trac-deb.lua | 206 + tex/context/base/trac-deb.tex | 43 + tex/context/base/trac-inf.lua | 149 + tex/context/base/trac-lmx.lua | 158 + tex/context/base/trac-lmx.tex | 16 + tex/context/base/trac-log.lua | 285 + tex/context/base/trac-tim.lua | 163 + tex/context/base/trac-tra.lua | 221 + tex/context/base/type-cow.tex | 4 +- tex/context/base/type-gyr.tex | 252 - tex/context/base/type-ini.mkii | 743 ++ tex/context/base/type-ini.mkiv | 705 ++ tex/context/base/type-ini.tex | 721 -- tex/context/base/type-mac.mkii | 220 + tex/context/base/type-mac.mkiv | 220 + tex/context/base/type-mac.tex | 434 + tex/context/base/type-map.tex | 48 +- tex/context/base/type-one.tex | 494 +- tex/context/base/type-otf.mkii | 535 + tex/context/base/type-otf.mkiv | 628 + tex/context/base/type-otf.tex | 739 +- tex/context/base/type-siz.mkii | 583 + tex/context/base/type-siz.mkiv | 375 + tex/context/base/type-siz.tex | 688 +- tex/context/base/type-syn.tex | 1 - tex/context/base/type-tmf.tex | 103 +- tex/context/base/type-win.tex | 120 + tex/context/base/type-xtx.tex | 2 +- tex/context/base/typo-brk.lua | 186 + tex/context/base/typo-brk.tex | 77 + tex/context/base/typo-cap.lua | 203 + tex/context/base/typo-cap.tex | 214 + tex/context/base/typo-ini.tex | 2 +- tex/context/base/typo-krn.lua | 218 + tex/context/base/typo-krn.tex | 59 + tex/context/base/typo-mir.lua | 409 + tex/context/base/typo-mir.tex | 144 + tex/context/base/typo-spa.lua | 149 + tex/context/base/typo-spa.tex | 69 + tex/context/base/unic-035.tex | 32 + tex/context/base/unic-exp.tex | 4 +- tex/context/base/unic-ini.mkii | 10 +- tex/context/base/unic-ini.mkiv | 19 +- tex/context/base/verb-c.tex | 2 +- tex/context/base/verb-eif.tex | 24 +- tex/context/base/verb-ini.tex | 2 +- tex/context/base/verb-js.tex | 18 +- tex/context/base/verb-jv.tex | 50 +- tex/context/base/verb-lua.lua | 10 +- tex/context/base/verb-mp.lua | 6 +- tex/context/base/verb-mp.tex | 2 +- tex/context/base/verb-pas.tex | 6 +- tex/context/base/verb-pl.tex | 58 +- tex/context/base/verb-sql.tex | 2 +- tex/context/base/verb-tex.lua | 6 +- tex/context/base/verb-tex.tex | 2 +- tex/context/base/verb-xml.tex | 2 +- tex/context/base/x-calcmath.lua | 191 +- tex/context/base/x-cals.mkiv | 15 +- tex/context/base/x-chemml.mkiv | 2 +- tex/context/base/x-ct.mkiv | 2 +- tex/context/base/x-fo.tex | 8 +- tex/context/base/x-mathml.lua | 77 +- tex/context/base/x-mathml.mkiv | 88 +- tex/context/base/x-newcml.tex | 8 +- tex/context/base/x-newmme.tex | 4 +- tex/context/base/x-newmml.mkii | 23 +- tex/context/base/x-newmml.tex | 2 +- tex/context/base/x-newmmo.tex | 2 +- tex/context/base/x-newpml.tex | 2 +- tex/context/base/x-set-02.tex | 11 +- tex/context/base/x-set-11.mkii | 2 +- tex/context/base/x-set-11.mkiv | 2 +- tex/context/base/x-set-11.tex | 2 +- tex/context/base/xetx-chr.tex | 1167 ++ tex/context/base/xetx-cls.tex | 378 + tex/context/base/xetx-ini.tex | 132 + tex/context/base/xetx-utf.tex | 1989 ++++ tex/context/base/xtag-cml.tex | 2 + tex/context/base/xtag-ent.tex | 2 +- tex/context/base/xtag-exp.tex | 6 +- tex/context/base/xtag-ext.tex | 4 +- tex/context/base/xtag-hyp.tex | 6 +- tex/context/base/xtag-ini.mkii | 6 - tex/context/base/xtag-ini.mkiv | 2 - tex/context/base/xtag-ini.tex | 24 +- tex/context/base/xtag-map.tex | 4 +- tex/context/base/xtag-mmc.tex | 8 +- tex/context/base/xtag-mml.tex | 8 +- tex/context/base/xtag-mmp.tex | 31 +- tex/context/base/xtag-pml.tex | 3 +- tex/context/base/xtag-pmu.tex | 4 +- tex/context/base/xtag-pre.tex | 4 +- tex/context/base/xtag-prs.tex | 2 +- tex/context/base/xtag-raw.tex | 6 +- tex/context/base/xtag-rng.tex | 14 +- tex/context/base/xtag-run.tex | 4 +- tex/context/base/xtag-stk.tex | 4 +- tex/context/base/xtag-utf.tex | 6 +- tex/context/bib/bibl-apa-fr.tex | 2 +- tex/context/bib/bibl-apa.tex | 6 +- tex/context/bib/t-bib.mkii | 5 + tex/context/bib/t-bib.mkiv | 64 + tex/context/bib/t-bib.tex | 74 +- tex/context/config/cont-usr.tex | 2 +- tex/context/interface/cont-cs.xml | 32 +- tex/context/interface/cont-cz.xml | 10033 ---------------- tex/context/interface/cont-de.xml | 32 +- tex/context/interface/cont-en.xml | 32 +- tex/context/interface/cont-fr.xml | 32 +- tex/context/interface/cont-it.xml | 32 +- tex/context/interface/cont-nl.xml | 32 +- tex/context/interface/cont-pe.xml | 32 +- tex/context/interface/cont-ro.xml | 32 +- tex/context/interface/keys-cs.xml | 57 + tex/context/interface/keys-de.xml | 57 + tex/context/interface/keys-en.xml | 57 + tex/context/interface/keys-fr.xml | 57 + tex/context/interface/keys-it.xml | 57 + tex/context/interface/keys-nl.xml | 57 + tex/context/interface/keys-pe.xml | 57 + tex/context/interface/keys-ro.xml | 57 + tex/context/interface/t-bib.xml | 3 + tex/context/patterns/lang-de.hyp | 4 +- tex/context/patterns/lang-de.pat | 5446 ++++----- tex/context/patterns/lang-de.rme | 8 +- tex/context/patterns/lang-deo.hyp | 4 +- tex/context/patterns/lang-deo.pat | 5446 +++++---- tex/context/patterns/lang-deo.rme | 8 +- tex/context/patterns/lang-uk.hyp | 8 + tex/context/patterns/lang-uk.pat | 1905 ++++ tex/context/patterns/lang-uk.rme | 70 + tex/context/test/context-test.tex | 27 + tex/context/user/cont-sys.rme | 9 +- tex/generic/context/luatex-basics.tex | 21 + tex/generic/context/luatex-fonts-merged.lua | 11070 ++++++++++++++++++ tex/generic/context/luatex-fonts.lua | 139 + tex/generic/context/luatex-fonts.tex | 139 + tex/generic/context/luatex-mplib.lua | 469 + tex/generic/context/luatex-mplib.tex | 118 + tex/generic/context/luatex-plain.tex | 25 + tex/generic/context/luatex-test.tex | 47 + tex/generic/context/ppchtex.noc | 4 +- tpm/t-bib.tpm | 8 +- web2c/context.cnf | 87 +- 1017 files changed, 240313 insertions(+), 120527 deletions(-) create mode 100644 context/data/cont-pe-scite.properties create mode 100644 context/data/context-bbedit-pe.xml create mode 100644 context/data/context-jedit-pe.xml delete mode 100644 fonts/enc/dvips/context/lm-ec-os.enc delete mode 100644 fonts/enc/dvips/context/lm-qx-os.enc delete mode 100644 fonts/enc/dvips/context/lm-qxtt-os.enc delete mode 100644 fonts/enc/dvips/context/lm-t5-os.enc delete mode 100644 fonts/enc/dvips/context/lm-texnansi-os.enc create mode 100644 fonts/enc/dvips/context/q-8r.enc create mode 100644 fonts/map/dvips/context/contnav.map create mode 100644 fonts/map/dvips/jmn/hans.map delete mode 100644 fonts/map/pdftex/context/cs-qbk.map delete mode 100644 fonts/map/pdftex/context/cs-qcs.map delete mode 100644 fonts/map/pdftex/context/cs-qpl.map delete mode 100644 fonts/map/pdftex/context/cs-qtm.map delete mode 100644 fonts/map/pdftex/context/ec-public-lm.map delete mode 100644 fonts/map/pdftex/context/ec-qbk.map delete mode 100644 fonts/map/pdftex/context/ec-qcs.map delete mode 100644 fonts/map/pdftex/context/ec-qpl.map delete mode 100644 fonts/map/pdftex/context/ec-qtm.map delete mode 100644 fonts/map/pdftex/context/el-public-lm.map delete mode 100644 fonts/map/pdftex/context/el-qbk.map delete mode 100644 fonts/map/pdftex/context/el-qcs.map delete mode 100644 fonts/map/pdftex/context/el-qpl.map delete mode 100644 fonts/map/pdftex/context/el-qtm.map delete mode 100644 fonts/map/pdftex/context/l7x-qbk.map delete mode 100644 fonts/map/pdftex/context/l7x-qcs.map delete mode 100644 fonts/map/pdftex/context/l7x-qpl.map delete mode 100644 fonts/map/pdftex/context/l7x-qtm.map delete mode 100644 fonts/map/pdftex/context/qx-public-lm.map delete mode 100644 fonts/map/pdftex/context/qx-qbk.map delete mode 100644 fonts/map/pdftex/context/qx-qcs.map delete mode 100644 fonts/map/pdftex/context/qx-qpl.map delete mode 100644 fonts/map/pdftex/context/qx-qtm.map delete mode 100644 fonts/map/pdftex/context/rm-qbk.map delete mode 100644 fonts/map/pdftex/context/rm-qcs.map delete mode 100644 fonts/map/pdftex/context/rm-qpl.map delete mode 100644 fonts/map/pdftex/context/rm-qtm.map delete mode 100644 fonts/map/pdftex/context/t2a-qbk.map delete mode 100644 fonts/map/pdftex/context/t2a-qcs.map delete mode 100644 fonts/map/pdftex/context/t2a-qpl.map delete mode 100644 fonts/map/pdftex/context/t2a-qtm.map delete mode 100644 fonts/map/pdftex/context/t2b-qbk.map delete mode 100644 fonts/map/pdftex/context/t2b-qcs.map delete mode 100644 fonts/map/pdftex/context/t2b-qpl.map delete mode 100644 fonts/map/pdftex/context/t2b-qtm.map delete mode 100644 fonts/map/pdftex/context/t2c-qbk.map delete mode 100644 fonts/map/pdftex/context/t2c-qcs.map delete mode 100644 fonts/map/pdftex/context/t2c-qpl.map delete mode 100644 fonts/map/pdftex/context/t2c-qtm.map delete mode 100644 fonts/map/pdftex/context/t5-public-lm.map delete mode 100644 fonts/map/pdftex/context/t5-qbk.map delete mode 100644 fonts/map/pdftex/context/t5-qcs.map delete mode 100644 fonts/map/pdftex/context/t5-qpl.map delete mode 100644 fonts/map/pdftex/context/t5-qtm.map delete mode 100644 fonts/map/pdftex/context/texnansi-public-lm.map delete mode 100644 fonts/map/pdftex/context/texnansi-qbk.map delete mode 100644 fonts/map/pdftex/context/texnansi-qcs.map delete mode 100644 fonts/map/pdftex/context/texnansi-qpl.map delete mode 100644 fonts/map/pdftex/context/texnansi-qtm.map delete mode 100644 fonts/map/pdftex/context/ts1-qbk.map delete mode 100644 fonts/map/pdftex/context/ts1-qcs.map delete mode 100644 fonts/map/pdftex/context/ts1-qpl.map delete mode 100644 fonts/map/pdftex/context/ts1-qtm.map create mode 100644 metapost/context/base/mp-chem.mp create mode 100644 scripts/context/lua/mtx-metatex.lua create mode 100644 scripts/context/lua/mtx-package.lua create mode 100644 scripts/context/lua/mtx-profile.lua create mode 100644 scripts/context/lua/mtx-server-ctx-fonttest.lua create mode 100644 scripts/context/lua/mtx-server-ctx-help.lua create mode 100644 scripts/context/lua/mtx-server-ctx-startup.lua create mode 100644 scripts/context/lua/mtx-timing.lua create mode 100644 scripts/context/lua/mtx-unzip.lua delete mode 100644 scripts/context/ruby/www/admin.rb delete mode 100644 scripts/context/ruby/www/common.rb delete mode 100644 scripts/context/ruby/www/dir.rb delete mode 100644 scripts/context/ruby/www/exa.rb delete mode 100644 scripts/context/ruby/www/lib.rb delete mode 100644 scripts/context/ruby/www/login.rb delete mode 100644 scripts/context/ruby/wwwclient.rb delete mode 100644 scripts/context/ruby/wwwserver.rb delete mode 100644 scripts/context/ruby/wwwwatch.rb delete mode 100755 scripts/context/stubs/mswin/exatools.bat create mode 100644 scripts/context/stubs/mswin/luatools.lua create mode 100644 scripts/context/stubs/mswin/metatex.cmd create mode 100644 scripts/context/stubs/mswin/mtxrun.lua create mode 100755 scripts/context/stubs/mswin/mtxtools.bat delete mode 100755 scripts/context/stubs/mswin/pdftrimwhite.bat create mode 100644 scripts/context/stubs/mswin/texexec.cmd delete mode 100755 scripts/context/stubs/mswin/texfind.bat create mode 100644 scripts/context/stubs/mswin/texmfstart.cmd delete mode 100755 scripts/context/stubs/mswin/texshow.bat delete mode 100755 scripts/context/stubs/unix/exatools create mode 100755 scripts/context/stubs/unix/luatools create mode 100755 scripts/context/stubs/unix/metatex create mode 100755 scripts/context/stubs/unix/mtxrun create mode 100755 scripts/context/stubs/unix/mtxtools delete mode 100755 scripts/context/stubs/unix/pdftrimwhite delete mode 100755 scripts/context/stubs/unix/texfind create mode 100755 scripts/context/stubs/unix/texmfstart delete mode 100755 scripts/context/stubs/unix/texshow create mode 100644 tex/context/base/back-ini.lua create mode 100644 tex/context/base/back-ini.tex create mode 100644 tex/context/base/back-pdf.lua create mode 100644 tex/context/base/back-pdf.tex create mode 100644 tex/context/base/bibl-bib.lua create mode 100644 tex/context/base/bibl-bib.tex create mode 100644 tex/context/base/bibl-tst.lua create mode 100644 tex/context/base/catc-act.tex create mode 100644 tex/context/base/catc-ctx.tex create mode 100644 tex/context/base/catc-def.tex create mode 100644 tex/context/base/catc-ini.lua create mode 100644 tex/context/base/catc-ini.mkii create mode 100644 tex/context/base/catc-ini.mkiv create mode 100644 tex/context/base/catc-sym.tex create mode 100644 tex/context/base/char-enc.lua create mode 100644 tex/context/base/char-enc.tex delete mode 100644 tex/context/base/char-syn.lua create mode 100644 tex/context/base/chem-ini.lua create mode 100644 tex/context/base/chem-ini.mkiv create mode 100644 tex/context/base/chem-str-test.tex create mode 100644 tex/context/base/chem-str.lua create mode 100644 tex/context/base/chem-str.mkiv create mode 100644 tex/context/base/colo-ext.mkii create mode 100644 tex/context/base/colo-ext.mkiv delete mode 100644 tex/context/base/colo-ext.tex create mode 100644 tex/context/base/colo-hex.mkii create mode 100644 tex/context/base/colo-hex.mkiv delete mode 100644 tex/context/base/colo-ini.tex create mode 100644 tex/context/base/context-base.lmx create mode 100644 tex/context/base/context-fonttest.lmx create mode 100644 tex/context/base/context-help.lmx create mode 100644 tex/context/base/context-timing.lmx create mode 100644 tex/context/base/context.rme delete mode 100644 tex/context/base/core-blk.lua delete mode 100644 tex/context/base/core-blk.mkiv delete mode 100644 tex/context/base/core-buf.tex delete mode 100644 tex/context/base/core-con.tex delete mode 100644 tex/context/base/core-ctx.tex create mode 100644 tex/context/base/core-def.mkii create mode 100644 tex/context/base/core-def.mkiv delete mode 100644 tex/context/base/core-def.tex create mode 100644 tex/context/base/core-env.mkii create mode 100644 tex/context/base/core-env.mkiv create mode 100644 tex/context/base/core-fld.mkii create mode 100644 tex/context/base/core-fld.mkiv delete mode 100644 tex/context/base/core-fld.tex create mode 100644 tex/context/base/core-fnt.mkii create mode 100644 tex/context/base/core-fnt.mkiv delete mode 100644 tex/context/base/core-fnt.tex delete mode 100644 tex/context/base/core-inc.tex create mode 100644 tex/context/base/core-int.mkii create mode 100644 tex/context/base/core-int.mkiv delete mode 100644 tex/context/base/core-int.tex delete mode 100644 tex/context/base/core-job.tex delete mode 100644 tex/context/base/core-ltb.tex create mode 100644 tex/context/base/core-mis.mkii create mode 100644 tex/context/base/core-mis.mkiv delete mode 100644 tex/context/base/core-mis.tex create mode 100644 tex/context/base/core-nav.mkii create mode 100644 tex/context/base/core-nav.mkiv delete mode 100644 tex/context/base/core-nav.tex delete mode 100644 tex/context/base/core-new.tex delete mode 100644 tex/context/base/core-ntb.tex delete mode 100644 tex/context/base/core-obj.tex delete mode 100644 tex/context/base/core-pos.tex delete mode 100644 tex/context/base/core-ref.lua delete mode 100644 tex/context/base/core-ref.mkii delete mode 100644 tex/context/base/core-ref.mkiv delete mode 100644 tex/context/base/core-reg.lua delete mode 100644 tex/context/base/core-reg.mkii delete mode 100644 tex/context/base/core-reg.mkiv delete mode 100644 tex/context/base/core-rul.tex delete mode 100644 tex/context/base/core-sec.mkii delete mode 100644 tex/context/base/core-sec.mkiv create mode 100644 tex/context/base/core-sec.tex delete mode 100644 tex/context/base/core-spa.tex delete mode 100644 tex/context/base/core-syn.lua delete mode 100644 tex/context/base/core-syn.mkii delete mode 100644 tex/context/base/core-syn.mkiv delete mode 100644 tex/context/base/core-sys.tex delete mode 100644 tex/context/base/core-tab.tex delete mode 100644 tex/context/base/core-tbl.tex delete mode 100644 tex/context/base/core-tsp.tex delete mode 100644 tex/context/base/core-two.tex delete mode 100644 tex/context/base/core-uti.tex delete mode 100644 tex/context/base/core-ver.tex create mode 100644 tex/context/base/data-aux.lua create mode 100644 tex/context/base/data-bin.lua create mode 100644 tex/context/base/data-con.lua create mode 100644 tex/context/base/data-crl.lua create mode 100644 tex/context/base/data-ctx.lua create mode 100644 tex/context/base/data-gen.lua create mode 100644 tex/context/base/data-inp.lua create mode 100644 tex/context/base/data-kps.lua create mode 100644 tex/context/base/data-lst.lua create mode 100644 tex/context/base/data-lua.lua create mode 100644 tex/context/base/data-out.lua create mode 100644 tex/context/base/data-pre.lua create mode 100644 tex/context/base/data-res.lua create mode 100644 tex/context/base/data-tex.lua create mode 100644 tex/context/base/data-tmf.lua create mode 100644 tex/context/base/data-tmp.lua create mode 100644 tex/context/base/data-tre.lua create mode 100644 tex/context/base/data-use.lua create mode 100644 tex/context/base/data-zip.lua delete mode 100644 tex/context/base/enco-ini.tex delete mode 100644 tex/context/base/enco-pfr.mkii delete mode 100644 tex/context/base/enco-pfr.mkiv delete mode 100644 tex/context/base/enco-utf.tex create mode 100644 tex/context/base/font-chk.lua create mode 100644 tex/context/base/font-cid.lua create mode 100644 tex/context/base/font-col.mkiv delete mode 100644 tex/context/base/font-col.tex create mode 100644 tex/context/base/font-ctx.lua create mode 100644 tex/context/base/font-dum.lua create mode 100644 tex/context/base/font-log.lua create mode 100644 tex/context/base/font-mis.lua create mode 100644 tex/context/base/font-ota.lua create mode 100644 tex/context/base/font-otb.lua create mode 100644 tex/context/base/font-otc.lua create mode 100644 tex/context/base/font-otd.lua create mode 100644 tex/context/base/font-oti.lua create mode 100644 tex/context/base/font-otn.lua create mode 100644 tex/context/base/font-otp.lua create mode 100644 tex/context/base/font-ott.lua create mode 100644 tex/context/base/font-tra.mkiv create mode 100644 tex/context/base/font-uni.mkii create mode 100644 tex/context/base/font-uni.mkiv delete mode 100644 tex/context/base/font-uni.tex create mode 100644 tex/context/base/font-unk.mkii create mode 100644 tex/context/base/font-unk.mkiv delete mode 100644 tex/context/base/font-unk.tex create mode 100644 tex/context/base/font-xtx.lua create mode 100644 tex/context/base/font-xtx.tex delete mode 100644 tex/context/base/hand-ini.tex create mode 100644 tex/context/base/java-ini.mkii create mode 100644 tex/context/base/java-ini.mkiv delete mode 100644 tex/context/base/java-ini.tex create mode 100644 tex/context/base/lang-cjk.tex delete mode 100644 tex/context/base/lang-ini.tex create mode 100644 tex/context/base/lang-lab.mkii create mode 100644 tex/context/base/lang-lab.mkiv delete mode 100644 tex/context/base/lang-lab.tex create mode 100644 tex/context/base/lang-spe.mkii create mode 100644 tex/context/base/lang-spe.mkiv delete mode 100644 tex/context/base/lang-spe.tex delete mode 100644 tex/context/base/lang-url.tex create mode 100644 tex/context/base/luat-bas.tex create mode 100644 tex/context/base/luat-cnf.lua create mode 100644 tex/context/base/luat-cod.tex delete mode 100644 tex/context/base/luat-crl.lua delete mode 100644 tex/context/base/luat-deb.lua delete mode 100644 tex/context/base/luat-deb.tex create mode 100644 tex/context/base/luat-dum.lua delete mode 100644 tex/context/base/luat-env.tex create mode 100644 tex/context/base/luat-fio.lua delete mode 100644 tex/context/base/luat-inp.lua delete mode 100644 tex/context/base/luat-kps.lua delete mode 100644 tex/context/base/luat-lib.lua delete mode 100644 tex/context/base/luat-lmx.lua delete mode 100644 tex/context/base/luat-lmx.tex delete mode 100644 tex/context/base/luat-log.lua create mode 100644 tex/context/base/luat-run.lua create mode 100644 tex/context/base/luat-soc.lua create mode 100644 tex/context/base/luat-sto.lua delete mode 100644 tex/context/base/luat-tex.lua delete mode 100644 tex/context/base/luat-tmp.lua delete mode 100644 tex/context/base/luat-tra.lua delete mode 100644 tex/context/base/luat-tre.lua delete mode 100644 tex/context/base/luat-uni.lua delete mode 100644 tex/context/base/luat-uni.tex delete mode 100644 tex/context/base/luat-zip.lua create mode 100644 tex/context/base/lxml-ent.lua create mode 100644 tex/context/base/lxml-mis.lua create mode 100644 tex/context/base/lxml-pth.lua create mode 100644 tex/context/base/lxml-tab.lua create mode 100644 tex/context/base/m-chemic.mkii create mode 100644 tex/context/base/m-chemic.mkiv delete mode 100644 tex/context/base/m-gamma.tex create mode 100644 tex/context/base/m-mkii.mkiv create mode 100644 tex/context/base/m-track.tex create mode 100644 tex/context/base/math-ali.mkiv create mode 100644 tex/context/base/math-arr.mkii create mode 100644 tex/context/base/math-arr.mkiv create mode 100644 tex/context/base/math-def.mkiv create mode 100644 tex/context/base/math-del.mkiv create mode 100644 tex/context/base/math-dim.lua create mode 100644 tex/context/base/math-dis.mkiv create mode 100644 tex/context/base/math-ext.lua delete mode 100644 tex/context/base/math-ext.tex create mode 100644 tex/context/base/math-for.mkiv create mode 100644 tex/context/base/math-frc.mkii create mode 100644 tex/context/base/math-frc.mkiv delete mode 100644 tex/context/base/math-ini.tex create mode 100644 tex/context/base/math-inl.mkiv create mode 100644 tex/context/base/math-int.mkiv create mode 100644 tex/context/base/math-map.lua delete mode 100644 tex/context/base/math-mis.tex create mode 100644 tex/context/base/math-noa.lua create mode 100644 tex/context/base/math-pln.mkii create mode 100644 tex/context/base/math-pln.mkiv delete mode 100644 tex/context/base/math-pln.tex create mode 100644 tex/context/base/math-run.mkii delete mode 100644 tex/context/base/math-run.tex create mode 100644 tex/context/base/math-scr.mkiv create mode 100644 tex/context/base/math-vfu.lua delete mode 100644 tex/context/base/meta-pdf.tex create mode 100644 tex/context/base/meta-pdh.lua create mode 100644 tex/context/base/metatex.tex create mode 100644 tex/context/base/mtx-context-arrange.tex create mode 100644 tex/context/base/mtx-context-combine.tex create mode 100644 tex/context/base/mtx-context-ideas.tex create mode 100644 tex/context/base/mtx-context-listing.tex create mode 100644 tex/context/base/mtx-context-timing.tex create mode 100644 tex/context/base/mult-chk.lua create mode 100644 tex/context/base/mult-chk.mkii create mode 100644 tex/context/base/mult-chk.mkiv create mode 100644 tex/context/base/mult-mcs.tex create mode 100644 tex/context/base/mult-mde.tex create mode 100644 tex/context/base/mult-men.tex create mode 100644 tex/context/base/mult-mes.lua create mode 100644 tex/context/base/mult-mfr.tex create mode 100644 tex/context/base/mult-mit.tex create mode 100644 tex/context/base/mult-mnl.tex create mode 100644 tex/context/base/mult-mno.tex create mode 100644 tex/context/base/mult-mpe.tex create mode 100644 tex/context/base/mult-mro.tex create mode 100644 tex/context/base/node-dum.lua create mode 100644 tex/context/base/node-ext.lua create mode 100644 tex/context/base/node-fin.lua create mode 100644 tex/context/base/node-fin.tex create mode 100644 tex/context/base/node-fnt.lua create mode 100644 tex/context/base/node-inj.lua create mode 100644 tex/context/base/node-pro.lua create mode 100644 tex/context/base/node-res.lua create mode 100644 tex/context/base/node-ser.lua create mode 100644 tex/context/base/node-shp.lua create mode 100644 tex/context/base/node-tex.lua create mode 100644 tex/context/base/node-tra.lua create mode 100644 tex/context/base/node-tsk.lua create mode 100644 tex/context/base/node-tst.lua create mode 100644 tex/context/base/norm-alo.tex create mode 100644 tex/context/base/norm-ctx.tex create mode 100644 tex/context/base/norm-etx.tex create mode 100644 tex/context/base/norm-ltx.tex create mode 100644 tex/context/base/norm-ptx.tex create mode 100644 tex/context/base/norm-tex.tex create mode 100644 tex/context/base/norm-xtx.tex create mode 100644 tex/context/base/page-bck.mkii create mode 100644 tex/context/base/page-bck.mkiv delete mode 100644 tex/context/base/page-bck.tex create mode 100644 tex/context/base/page-ini.mkii create mode 100644 tex/context/base/page-ini.mkiv delete mode 100644 tex/context/base/page-ini.tex create mode 100644 tex/context/base/page-mis.tex create mode 100644 tex/context/base/page-one.mkii create mode 100644 tex/context/base/page-one.mkiv delete mode 100644 tex/context/base/page-one.tex create mode 100644 tex/context/base/page-txt.mkii create mode 100644 tex/context/base/page-txt.mkiv delete mode 100644 tex/context/base/page-txt.tex create mode 100644 tex/context/base/ppchtex.mkii create mode 100644 tex/context/base/ppchtex.mkiv delete mode 100644 tex/context/base/ppchtex.tex create mode 100644 tex/context/base/prop-ini.mkii create mode 100644 tex/context/base/prop-ini.mkiv delete mode 100644 tex/context/base/prop-ini.tex delete mode 100644 tex/context/base/prop-lay.tex delete mode 100644 tex/context/base/prop-mis.tex delete mode 100644 tex/context/base/prop-run.tex delete mode 100644 tex/context/base/regi-ini.tex create mode 100644 tex/context/base/s-fnt-11.tex create mode 100644 tex/context/base/s-fnt-20.tex create mode 100644 tex/context/base/s-fnt-21.tex create mode 100644 tex/context/base/s-fnt-23.tex create mode 100644 tex/context/base/s-fnt-24.tex create mode 100644 tex/context/base/s-fnt-25.tex create mode 100644 tex/context/base/s-fnt-30.tex create mode 100644 tex/context/base/s-pre-66.tex create mode 100644 tex/context/base/s-reg-01.tex create mode 100644 tex/context/base/scrp-cjk.lua create mode 100644 tex/context/base/scrp-ini.lua create mode 100644 tex/context/base/scrp-ini.tex delete mode 100644 tex/context/base/sort-def.mkii delete mode 100644 tex/context/base/sort-def.mkiv delete mode 100644 tex/context/base/sort-ini.tex delete mode 100644 tex/context/base/sort-lan.mkii delete mode 100644 tex/context/base/sort-lan.mkiv delete mode 100644 tex/context/base/spec-def.mkii delete mode 100644 tex/context/base/spec-def.mkiv delete mode 100644 tex/context/base/spec-fdf.mkii delete mode 100644 tex/context/base/spec-fdf.mkiv delete mode 100644 tex/context/base/spec-pdf.lua delete mode 100644 tex/context/base/spec-tpd.mkii delete mode 100644 tex/context/base/spec-tpd.mkiv create mode 100644 tex/context/base/strc-bkm.lua create mode 100644 tex/context/base/strc-bkm.tex create mode 100644 tex/context/base/strc-blk.lua create mode 100644 tex/context/base/strc-blk.tex create mode 100644 tex/context/base/strc-def.tex create mode 100644 tex/context/base/strc-des.lua create mode 100644 tex/context/base/strc-des.tex create mode 100644 tex/context/base/strc-doc.lua create mode 100644 tex/context/base/strc-doc.tex create mode 100644 tex/context/base/strc-flt.lua create mode 100644 tex/context/base/strc-flt.tex create mode 100644 tex/context/base/strc-ini.lua create mode 100644 tex/context/base/strc-ini.tex create mode 100644 tex/context/base/strc-itm.lua create mode 100644 tex/context/base/strc-itm.tex create mode 100644 tex/context/base/strc-lst.lua create mode 100644 tex/context/base/strc-lst.tex create mode 100644 tex/context/base/strc-mar.lua create mode 100644 tex/context/base/strc-mar.tex create mode 100644 tex/context/base/strc-mat.lua create mode 100644 tex/context/base/strc-mat.tex create mode 100644 tex/context/base/strc-not.lua create mode 100644 tex/context/base/strc-not.tex create mode 100644 tex/context/base/strc-num.lua create mode 100644 tex/context/base/strc-num.tex create mode 100644 tex/context/base/strc-pag.lua create mode 100644 tex/context/base/strc-pag.tex create mode 100644 tex/context/base/strc-prc.lua create mode 100644 tex/context/base/strc-prc.tex create mode 100644 tex/context/base/strc-ref.lua create mode 100644 tex/context/base/strc-ref.tex create mode 100644 tex/context/base/strc-reg.lua create mode 100644 tex/context/base/strc-reg.tex create mode 100644 tex/context/base/strc-ren.tex create mode 100644 tex/context/base/strc-sbe.tex create mode 100644 tex/context/base/strc-sec.tex create mode 100644 tex/context/base/strc-syn.lua create mode 100644 tex/context/base/strc-syn.tex create mode 100644 tex/context/base/strc-xml.tex create mode 100644 tex/context/base/supp-dir.mkii create mode 100644 tex/context/base/supp-dir.mkiv delete mode 100644 tex/context/base/supp-dir.tex delete mode 100644 tex/context/base/supp-fil.tex delete mode 100644 tex/context/base/supp-ini.tex create mode 100644 tex/context/base/supp-ran.lua create mode 100644 tex/context/base/supp-ran.mkii create mode 100644 tex/context/base/supp-ran.mkiv delete mode 100644 tex/context/base/supp-ran.tex create mode 100644 tex/context/base/syst-aux.tex delete mode 100644 tex/context/base/syst-cat.mkii delete mode 100644 tex/context/base/syst-cat.mkiv delete mode 100644 tex/context/base/syst-cat.tex delete mode 100644 tex/context/base/syst-chr.tex delete mode 100644 tex/context/base/syst-con.tex delete mode 100644 tex/context/base/syst-etx.tex create mode 100644 tex/context/base/syst-fnt.mkii create mode 100644 tex/context/base/syst-fnt.mkiv delete mode 100644 tex/context/base/syst-fnt.tex create mode 100644 tex/context/base/syst-ini.tex create mode 100644 tex/context/base/syst-lua.lua create mode 100644 tex/context/base/syst-lua.tex delete mode 100644 tex/context/base/syst-mtx.tex delete mode 100644 tex/context/base/syst-omg.tex delete mode 100644 tex/context/base/syst-pdt.tex delete mode 100644 tex/context/base/syst-prm.tex delete mode 100644 tex/context/base/syst-rtp.tex delete mode 100644 tex/context/base/syst-str.tex delete mode 100644 tex/context/base/syst-var.tex delete mode 100644 tex/context/base/syst-xtx.tex create mode 100644 tex/context/base/tabl-ltb.tex create mode 100644 tex/context/base/tabl-ntb.mkii create mode 100644 tex/context/base/tabl-ntb.mkiv create mode 100644 tex/context/base/tabl-nte.tex create mode 100644 tex/context/base/tabl-pln.tex create mode 100644 tex/context/base/tabl-tab.tex create mode 100644 tex/context/base/tabl-tbl.tex create mode 100644 tex/context/base/tabl-tsp.tex create mode 100644 tex/context/base/task-ini.lua create mode 100644 tex/context/base/task-ini.tex create mode 100644 tex/context/base/trac-deb.lua create mode 100644 tex/context/base/trac-deb.tex create mode 100644 tex/context/base/trac-inf.lua create mode 100644 tex/context/base/trac-lmx.lua create mode 100644 tex/context/base/trac-lmx.tex create mode 100644 tex/context/base/trac-log.lua create mode 100644 tex/context/base/trac-tim.lua create mode 100644 tex/context/base/trac-tra.lua delete mode 100644 tex/context/base/type-gyr.tex create mode 100644 tex/context/base/type-ini.mkii create mode 100644 tex/context/base/type-ini.mkiv delete mode 100644 tex/context/base/type-ini.tex create mode 100644 tex/context/base/type-mac.mkii create mode 100644 tex/context/base/type-mac.mkiv create mode 100644 tex/context/base/type-mac.tex create mode 100644 tex/context/base/type-otf.mkii create mode 100644 tex/context/base/type-otf.mkiv create mode 100644 tex/context/base/type-siz.mkii create mode 100644 tex/context/base/type-siz.mkiv create mode 100644 tex/context/base/type-win.tex create mode 100644 tex/context/base/typo-brk.lua create mode 100644 tex/context/base/typo-brk.tex create mode 100644 tex/context/base/typo-cap.lua create mode 100644 tex/context/base/typo-cap.tex create mode 100644 tex/context/base/typo-krn.lua create mode 100644 tex/context/base/typo-krn.tex create mode 100644 tex/context/base/typo-mir.lua create mode 100644 tex/context/base/typo-mir.tex create mode 100644 tex/context/base/typo-spa.lua create mode 100644 tex/context/base/typo-spa.tex create mode 100644 tex/context/base/unic-035.tex create mode 100644 tex/context/base/xetx-chr.tex create mode 100644 tex/context/base/xetx-cls.tex create mode 100644 tex/context/base/xetx-ini.tex create mode 100644 tex/context/base/xetx-utf.tex delete mode 100644 tex/context/base/xtag-ini.mkii delete mode 100644 tex/context/base/xtag-ini.mkiv create mode 100644 tex/context/bib/t-bib.mkii create mode 100644 tex/context/bib/t-bib.mkiv delete mode 100644 tex/context/interface/cont-cz.xml create mode 100644 tex/context/patterns/lang-uk.hyp create mode 100644 tex/context/patterns/lang-uk.pat create mode 100644 tex/context/patterns/lang-uk.rme create mode 100644 tex/context/test/context-test.tex create mode 100644 tex/generic/context/luatex-basics.tex create mode 100644 tex/generic/context/luatex-fonts-merged.lua create mode 100644 tex/generic/context/luatex-fonts.lua create mode 100644 tex/generic/context/luatex-fonts.tex create mode 100644 tex/generic/context/luatex-mplib.lua create mode 100644 tex/generic/context/luatex-mplib.tex create mode 100644 tex/generic/context/luatex-plain.tex create mode 100644 tex/generic/context/luatex-test.tex 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 @@ +BBLMKeywordList \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-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 @@ + + 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.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 Binary files a/doc/context/bib/bibmod-doc.pdf and b/doc/context/bib/bibmod-doc.pdf 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/lm-texnansi-os.enc deleted file mode 100644 index 059dd788b..000000000 --- a/fonts/enc/dvips/context/lm-texnansi-os.enc +++ /dev/null @@ -1,258 +0,0 @@ -/enclmtexnansi[ -/.notdef -/Euro -/.notdef -/.notdef -/fraction -/dotaccent -/hungarumlaut -/ogonek -/fl -/.notdef -/cwm -/ff -/fi -/.notdef -/ffi -/ffl -/dotlessi -/dotlessj -/grave -/acute -/caron -/breve -/macron -/ring -/cedilla -/germandbls -/ae -/oe -/oslash -/AE -/OE -/Oslash -/space -/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 -/circumflex -/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 -/tilde -/dieresis -/Lslash -/quotesingle -/quotesinglbase -/florin -/quotedblbase -/ellipsis -/dagger -/daggerdbl -/circumflex.dup -/perthousand -/Scaron -/guilsinglleft -/OE.dup -/Zcaron -/asciicircum -/minus -/lslash -/quoteleft.dup -/quoteright.dup -/quotedblleft -/quotedblright -/bullet -/endash -/emdash -/tilde.dup -/trademark -/scaron -/guilsinglright -/oe.dup -/zcaron -/asciitilde -/Ydieresis -/nbspace -/exclamdown -/cent -/sterling -/currency -/yen -/brokenbar -/section -/dieresis.dup -/copyright -/ordfeminine -/guillemotleft -/logicalnot -/sfthyphen -/registered -/macron.dup -/degree -/plusminus -/twosuperior -/threesuperior -/acute.dup -/mu -/paragraph -/periodcentered -/cedilla.dup -/onesuperior -/ordmasculine -/guillemotright -/onequarter -/onehalf -/threequarters -/questiondown -/Agrave -/Aacute -/Acircumflex -/Atilde -/Adieresis -/Aring -/AE.dup -/Ccedilla -/Egrave -/Eacute -/Ecircumflex -/Edieresis -/Igrave -/Iacute -/Icircumflex -/Idieresis -/Eth -/Ntilde -/Ograve -/Oacute -/Ocircumflex -/Otilde -/Odieresis -/multiply -/Oslash.dup -/Ugrave -/Uacute -/Ucircumflex -/Udieresis -/Yacute -/Thorn -/germandbls.dup -/agrave -/aacute -/acircumflex -/atilde -/adieresis -/aring -/ae.dup -/ccedilla -/egrave -/eacute -/ecircumflex -/edieresis -/igrave -/iacute -/icircumflex -/idieresis -/eth -/ntilde -/ograve -/oacute -/ocircumflex -/otilde -/odieresis -/divide -/oslash.dup -/ugrave -/uacute -/ucircumflex -/udieresis -/yacute -/thorn -/ydieresis -] def diff --git a/fonts/enc/dvips/context/q-8r.enc b/fonts/enc/dvips/context/q-8r.enc new file mode 100644 index 000000000..be8b32613 --- /dev/null +++ b/fonts/enc/dvips/context/q-8r.enc @@ -0,0 +1,264 @@ +% 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 +/dotaccent +/fi +/fl +/fraction +/hungarumlaut +/Lslash +/lslash +/ogonek +/ring +/.notdef +/breve +/minus +/.notdef +/Zcaron +/zcaron +/caron +/dotlessi +/dotlessj +/ff +/ffi +/ffl +/notequal +/infinity +/lessequal +/greaterequal +/partialdiff +/summation +/product +/pi +/grave +/quotesingle +/space +/exclam +/quotedbl +/numbersign +/dollar +/percent +/ampersand +/quoteright +/parenleft +/parenright +/asterisk +/plus +/comma +/hyphen +/period +/slash +/zero +/one +/two +/three +/four +/five +/six +/seven +/eight +/nine +/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 +/.notdef +/Euro +/integral +/quotesinglbase +/florin +/quotedblbase +/ellipsis +/dagger +/daggerdbl +/circumflex +/perthousand +/Scaron +/guilsinglleft +/OE +/Omega +/radical +/approxequal +/.notdef +/.notdef +/.notdef +/quotedblleft +/quotedblright +/bullet +/endash +/emdash +/tilde +/trademark +/scaron +/guilsinglright +/oe +/Delta +/lozenge +/Ydieresis +/.notdef +/exclamdown +/cent +/sterling +/currency +/yen +/brokenbar +/section +/dieresis +/copyright +/ordfeminine +/guillemotleft +/logicalnot +/hyphen +/registered +/macron +/degree +/plusminus +/two.superior +/three.superior +/acute +/mu +/paragraph +/periodcentered +/cedilla +/one.superior +/ordmasculine +/guillemotright +/onequarter +/onehalf +/threequarters +/questiondown +/Agrave +/Aacute +/Acircumflex +/Atilde +/Adieresis +/Aring +/AE +/Ccedilla +/Egrave +/Eacute +/Ecircumflex +/Edieresis +/Igrave +/Iacute +/Icircumflex +/Idieresis +/Eth +/Ntilde +/Ograve +/Oacute +/Ocircumflex +/Otilde +/Odieresis +/multiply +/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 +/divide +/oslash +/ugrave +/uacute +/ucircumflex +/udieresis +/yacute +/thorn +/ydieresis +] def 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 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])=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)) : + if (not check_multi_par_chain) or + ((nxy[fpos]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) + +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 --- filename : l-lpeg.lua --- 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-lpeg'] = 1.001 +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 + + +end -- of closure --- 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 +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" +} -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 = "\\", ";" @@ -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,24 +1383,28 @@ 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 - --- a,b,c,d,e,f = number.toset(100101) - -function number.toset(n) - return (tostring(n)):match("(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)") -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) + +function number.toset(n) + return (tostring(n)):match("(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)") +end + 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 + +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 +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 - 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 { } + 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("//+","/") - 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 + return a .. gsub(b,"//+","/") end + return (gsub(pth,"//+","/")) 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 + +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 --- filename : l-url.lua --- 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 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): -- @@ -1843,29 +1997,28 @@ if not url then url = { } end -- / \ / \ -- urn:example:animal:ferret:nose -do - - local function tochar(s) - return string.char(tonumber(s,16)) - end +url = url or { } - local colon, qmark, hash, slash, percent, endofstring = lpeg.P(":"), lpeg.P("?"), lpeg.P("#"), lpeg.P("/"), lpeg.P("%"), lpeg.P(-1) +local function tochar(s) + return char(tonumber(s,16)) +end - local hexdigit = lpeg.R("09","AF","af") - local escaped = percent * lpeg.C(hexdigit * hexdigit) / tochar +local colon, qmark, hash, slash, percent, endofstring = lpeg.P(":"), lpeg.P("?"), lpeg.P("#"), lpeg.P("/"), lpeg.P("%"), lpeg.P(-1) - 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 hexdigit = lpeg.R("09","AF","af") +local plus = lpeg.P("+") +local escaped = (plus / " ") + (percent * lpeg.C(hexdigit * hexdigit) / tochar) - local parser = lpeg.Ct(scheme * authority * path * query * fragment) +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("") - 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 + +dir.makedirs = dir.mkdirs + -end end +end -- of closure +do -- create closure to overcome 200 locals limit --- 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 @@ -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 + +do -- create closure to overcome 200 locals limit -if not versions then versions = { } end versions['l-unicode'] = 1.001 -if not unicode then unicode = { } end +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" +} -local concat, utfchar, utfgsub = table.concat, unicode.utf8.char, unicode.utf8.gsub -local char, byte = string.char, string.byte +utf = utf or unicode.utf8 -if not garbagecollector then - garbagecollector = { - push = function() collectgarbage("stop") end, - pop = function() collectgarbage("restart") end, - } -end +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 + +do -- create closure to overcome 200 locals limit -if not versions then versions = { } end versions['l-math'] = 1.001 +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) @@ -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 + + +end -- of closure --- 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 +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" +} -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 @@ -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 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 '' + 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,279 +3260,163 @@ if arg then end +-- weird place ... depends on a not yet loaded module -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 +function environment.texfile(filename) + return resolvers.find_file(filename,'tex') +end --- 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. +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 --- 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. +environment.loadedluacode = loadfile -- can be overloaded --- Beware, loading and saving is overloaded in luat-tmp! +--~ 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 -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' } +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 --- here we catch a few new thingies (todo: add these paths to context.tmf) --- --- FONTFEATURES = .;$TEXMF/fonts/fea// --- FONTCIDMAPS = .;$TEXMF/fonts/cid// +-- the next ones can use the previous ones / combine -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? +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 - 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 + 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 - 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") + return false end --- backward compatible ones -input.alternatives = { } +end -- of closure -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' +do -- create closure to overcome 200 locals limit --- obscure ones +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" +} -input.formats ['misc fonts'] = '' -input.suffixes['misc fonts'] = { } +local format = string.format -input.formats ['sfd'] = 'SFDFONTS' -input.suffixes ['sfd'] = { 'sfd' } -input.alternatives['subfont definition files'] = 'sfd' +local statusinfo, n, registered = { }, 0, { } --- 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 +statistics = statistics or { } -function input.settrace(n) - input.trace = tonumber(n or 0) - if input.trace > 0 then - input.verbose = true - end -end +statistics.enable = true +statistics.threshold = 0.05 -input.log = (texio and texio.write_nl) or print +-- timing functions -function input.report(...) - if input.verbose then - input.log("<<"..format(...)..">>") - end -end +local clock = os.gettimeofday or os.clock -function input.report(...) - if input.trace > 0 then -- extra test - input.log("<<"..format(...)..">>") - end +function statistics.hastimer(instance) + return instance and instance.starttime 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.starttiming(instance) - if instance then +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 input.stoptiming(instance, report) - if instance then +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() @@ -3098,1032 +3424,727 @@ do instance.stoptime = stoptime instance.loadtime = instance.loadtime + loadtime if report then - input.report("load time %0.3f",loadtime) + statistics.report("load time %0.3f",loadtime) end + instance.timing = 0 return loadtime end end - return 0 end - + return 0 end -function input.elapsedtime(instance) +function statistics.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 +function statistics.elapsedindeed(instance) + local t = (instance and instance.loadtime) or 0 + return t > statistics.threshold end -input.loadtime = input.elapsedtime +-- general function -function input.env(key) - return input.instance.environment[key] or input.osenv(key) +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 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) +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 - ie[key] = value + statistics.enable = false 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) +function statistics.show_job_stat(tag,data,n) + texio.write_nl(format("%-15s: %s - %s","mkiv lua stats",tag:rpadd(n," "),data)) +end -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 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 -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 +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 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 +function statistics.runtime() + statistics.stoptiming(statistics) + return statistics.formatruntime(statistics.elapsedtime(statistics)) 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 +function statistics.formatruntime(runtime) + return format("%s seconds", statistics.elapsedtime(statistics)) 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() +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 -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 -- 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-- +

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 structured file. Actually, any logging that +is hooked into callbacks will be \XML\ by default.

+--ldx]]-- + +logs = logs or { } +logs.xml = logs.xml or { } +logs.tex = logs.tex or { } + +--[[ldx-- +

This looks pretty ugly but we need to speed things up a bit.

+--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 - 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 +-- tex logging + +function logs.tex.report(category,fmt,...) -- new + if fmt then + write_nl(category .. " | " .. format(fmt,...)) + else + write_nl(category .. " |") 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 +function logs.tex.line(fmt,...) -- new + if fmt then + write_nl(format(fmt,...)) 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 + write_nl("") end end --- database loading +local texcount = tex and tex.count -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() +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 - input.loadlists() - if instance.renewcache then - input.savefiles() - end + write("[-") 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 } ) +function logs.tex.stop_page_number() + write("]") end -function input.aux.prepend_hash(type,tag,name) - if input.trace > 0 then - input.logger("= hash prepend: %s",tag) +logs.tex.report_job_stat = statistics.show_job_stat + +-- xml logging + +function logs.xml.report(category,fmt,...) -- new + if fmt then + write_nl(format("%s",category,format(fmt,...))) + else + write_nl(format("",category)) 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 +function logs.xml.line(fmt,...) -- new + if fmt then + write_nl(format("%s",format(fmt,...))) else - -- weird + write_nl("") end - input.expand_variables() - input.reset_hashes() end --- locators +function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end +function logs.xml.stop () if logs.level > 0 then tw("") end end +function logs.xml.push () if logs.level > 0 then tw("" ) end end -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 +function logs.xml.start_run() + write_nl("") + write_nl("") -- xmlns='www.pragma-ade.com/luatex/schemas/context-job.rng' + write_nl("") end -function input.locatedatabase(specification) - return input.methodhandler('locators', specification) +function logs.xml.stop_run() + write_nl("") 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 +function logs.xml.start_page_number() + write_nl(format("

") + write_nl("") +end -function input.hashdatabase(tag,name) - return input.methodhandler('hashers',tag,name) +function logs.xml.report_output_pages(p,b) + write_nl(format("", p)) + write_nl(format("", b)) + write_nl("") 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 +function logs.xml.report_output_log() end -function input.hashers.tex(tag,name) - input.aux.load_files(tag) +function logs.xml.report_tex_stat(k,v) + texiowrite_nl("log",""..tostring(v).."") end --- generators: +local level = 0 -function input.loadlists() - for _, hash in ipairs(input.instance.hashes) do - input.generatedatabase(hash.tag) - end +function logs.xml.show_open(name) + level = level + 1 + texiowrite_nl(format("",level,name)) end -function input.generatedatabase(specification) - return input.methodhandler('generators', specification) +function logs.xml.show_close(name) + texiowrite(" ") + level = level - 1 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 +function logs.xml.show_load(name) + texiowrite_nl(format("",level+1,name)) 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. +local name, banner = 'report', 'context' -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 +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 -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 +local function simple(fmt,...) + if fmt then + write_nl(format("%s | %s",name,format(fmt,...))) + else + write_nl(format("%s |",name)) end end -function input.split_path(str) - if type(str) == 'table' then - return str - else - return file.split_path(str) + +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 input.join_path(str) - if type(str) == 'table' then - return file.join_path(str) + +function logs.setverbose(what) + if what then + trackers.enable("resolvers.verbose") else - return str + trackers.disable("resolvers.verbose") end + logs.verbose = what or false 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 +function logs.extendbanner(_banner_,_verbose_) + banner = banner .. " | ".. _banner_ + if _verbose_ ~= nil then + logs.setverbose(what) end end --- end of split/join code +logs.verbose = false +logs.report = logs.tex.report +logs.simple = logs.tex.report -function input.saveoldconfig() - input.splitconfig() - input.aux.save_data('configuration', nil) - input.joinconfig() +function logs.reportlines(str) -- todo: + for line in str:gmatch("(.-)[\n\r]") do + logs.report(line) + end 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") +function logs.reportline() -- for scripts too + logs.report() end -if not texmf then texmf = {} end -- no longer needed, at least not here +logs.simpleline = logs.reportline -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 +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 -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 +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 - input.report("skipping %s for %s from %s",dataname,pathname,filename) - instance[dataname][pathname] = { } - instance.loaderror = true + sleep(0.1) 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) +--~ 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: -- --- first texmfcnf.lua files are located, next the cached texmf.cnf files +-- * support for reading lsr files +-- * selective scanning (subtrees) +-- * some public auxiliary functions were made private -- --- return { --- TEXMFBOGUS = 'effe checken of dit werkt', --- } +-- 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 -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 +-- 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. -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 +-- 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. -function input.resetconfig() - input.identify_own() - local instance = input.instance - instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false +-- 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 -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 +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' } -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 +-- backward compatible ones -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 +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' -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 +-- obscure ones -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 +formats ['misc fonts'] = '' +suffixes['misc fonts'] = { } -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 +formats ['sfd'] = 'SFDFONTS' +suffixes ['sfd'] = { 'sfd' } +alternatives['subfont definition files'] = 'sfd' -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 +-- 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 -end -function input.is_variable(name) - return input.aux.is_entry(input.instance.variables,name) -end + return newinstance -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) +function resolvers.setinstance(someinstance) + instance = someinstance + resolvers.instance = someinstance + return someinstance end -function input.unexpanded_path(str) - return file.join_path(input.unexpanded_path_list(str)) +function resolvers.reset() + return resolvers.setinstance(resolvers.newinstance()) end -do - local done = { } +local function reset_hashes() + instance.lists = { } + instance.found = { } +end - 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 = { }, { } +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 - - 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 + 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 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)) +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 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])) +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 t + return value or "" end -function input.expand_path(str) - return file.join_path(input.expanded_path_list(str)) +function resolvers.env(key) + return instance.environment[key] or resolvers.osenv(key) 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' +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.variable_of_format(str) - return input.formats[str] or input.formats[input.alternatives[str]] or '' +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 -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] +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 '' + 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) +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} @@ -4146,2363 +4167,2168 @@ end -- work that well; the parsing is ok, but dealing with the resulting -- table is a pain because we need to work inside-out recursively -function input.aux.splitpathexpr(str, t, validate) - -- no need for optimization, only called a few times, we can use lpeg for the sub +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 = str:gsub(",}",",@}") - str = str:gsub("{,","{@,") + 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 - local done = false + 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 + str, ok = gsub(str,"([^{},]+){([^{}]+)}",do_first) + if ok > 0 then done = true else 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 + str, ok = gsub(str,"{([^{}]+)}([^{},]+)",do_second) + if ok > 0 then done = true else 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 + str, ok = gsub(str,"{([^{}]+)}{([^{}]+)}",do_both) + if ok > 0 then done = true else break end end - str = str:gsub("({[^{}]*){([^{}]+)}([^{}]*})", function(a,b,c) - done = true - return a .. b.. c - end) + str, ok = gsub(str,"({[^{}]*){([^{}]+)}([^{}]*})",do_three) + if ok > 0 then done = true end if not done then break end end - str = str:gsub("[{}]", "") - str = str:gsub("@","") + str = gsub(str,"[{}]", "") + str = gsub(str,"@","") if validate then - for s in str:gmatch("[^,]+") do + for s in gmatch(str,"[^,]+") do s = validate(s) if s then t[#t+1] = s end end else - for s in str:gmatch("[^,]+") do + for s in gmatch(str,"[^,]+") 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 +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 _,v in ipairs(pathlist) do - if v:find("[{}]") then + for k=1,#pathlist do + if find(pathlist[k],"[{}]") 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) + 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 _,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 + 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 -input.is_readable = { } +-- 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 input.aux.is_readable(readable, name) - if input.trace > 2 then - if readable then - input.logger("+ readable: %s",name) +function resolvers.getownpath() + if not resolvers.ownpath then + if resolvers.autoselfdir and os.selfdir then + resolvers.ownpath = os.selfdir else - input.logger("- readable: %s", name) + 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 readable -end - -function input.is_readable.file(name) - return input.aux.is_readable(lfs.isfile(name), name) + return resolvers.ownpath end -input.is_readable.tex = input.is_readable.file - --- name --- name/name +local own_places = { "SELFAUTOLOC", "SELFAUTODIR", "SELFAUTOPARENT", "TEXMFCNF" } -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 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 dname == "" or dname:find("^%.") then - dname = false - else - dname = "/" .. dname .. "$" + if not instance.configuration[dname] then + instance.configuration[dname] = { } + instance.order[#instance.order+1] = instance.configuration[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] + 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 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 + 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 - elseif input.trace > 1 then - input.logger('! blobpath no: %s (%s)',blobpath,bname) + else + break end end + f:close() + elseif trace_verbose then + logs.report("fileio","skipping %s", fname) end end - if #filelist > 0 then - return filelist - else - return nil +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 input.suffix_of_format(str) - if input.suffixes[str] then - return input.suffixes[str][1] +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 - return "" + 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 input.suffixes_of_format(str) - if input.suffixes[str] then - return input.suffixes[str] +function resolvers.load_lua() + if #instance.luafiles == 0 then + -- yet harmless else - return {} + 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 -do +-- database loading - -- called about 700 times for an empty doc (font initializations etc) - -- i need to weed the font files for redundant calls +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 - local letter = lpeg.R("az","AZ") - local separator = lpeg.P("://") +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 - local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator - local rootbased = lpeg.P("/") + letter*lpeg.P(":") +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 - -- ./name ../name /name c: :// - function input.aux.qualified_path(filename) - return qualified:match(filename) +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 - function input.aux.rootbased_path(filename) - return rootbased:match(filename) + 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 input.normalize_name(original) - return original +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 - input.normalize_name = file.collapse_path +-- hashers +function resolvers.hashdatabase(tag,name) + return resolvers.methodhandler('hashers',tag,name) 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 +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 --- split the next one up, better for jit +function resolvers.hashers.tex(tag,name) + resolvers.load_data(tag,'files') +end -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 +-- generators: + +function resolvers.loadlists() + for _, hash in ipairs(instance.hashes) do + resolvers.generatedatabase(hash.tag) 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 } +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 - 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) + 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 - result, ok = { forcedname }, true - break end end + elseif mode == 'directory' then + m = m + 1 + if path then + action(path..'/'..name) + else + action(name) + 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 + 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 - else - if ext == "" then - for _, s in pairs(input.suffixes_of_format(instance.format)) do - wantedfiles[#wantedfiles+1] = filename .. "." .. s - 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 - filetype = instance.format - if input.trace > 0 then - input.logger('! using given filetype: %s',filetype) + 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 - 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 + if #t > 1 then + ie[k] = t 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 + ie[k] = t[1] 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 +-- end of split/join code -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 +function resolvers.saveoldconfig() + resolvers.splitconfig() + resolvers.save_data('configuration') + resolvers.joinconfig() 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 +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 - instance.fakepaths[name] = 2 -- no directory + return m .. "['" .. k .. "']={'" .. concat(v,"','").. "'}," 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] + 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 - 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 + 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 - return result -end - -function input.find_given_file(filename) - return (input.find_given_files(filename)[1] or "") + t[#t+1] = "}" + return concat(t,"\n") 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 +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 - 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 + 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 - 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 + elseif trace_verbose then + logs.report("fileio","unable to save %s in %s (access error)",dataname,luaname) 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("\n") - f:write("\n") - if jobname then - f:write("\t" .. jobname .. "\n") - end - f:write("\t\n") - for _,v in pairs(sorted(instance.foundintrees)) do -- ipairs - f:write("\t\t" .. v .. "\n") +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 - f:write("\t\n") - f:write("\n") - f:close() + elseif trace_verbose then + logs.report("fileio","skipping %s for %s from %s",dataname,pathname,filename) end end -function input.automount() - -- implemented later -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.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.resetconfig() + identify_own() + instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false 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) +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 - for _,v in pairs(result) do - report(v) + 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 --- 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))) +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 --- 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 } +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 - files[name] = path + expansions[k] = v 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) + for k,v in next, environment do -- move environment to expansions + if not expansions[k] then expansions[k] = v end 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 + for k,v in next, variables do -- move variables to expansions + if not expansions[k] then expansions[k] = v end 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)) + 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 - return input[what][scheme](filename,filetype) -- todo: specification - else - return input[what].tex(filename,filetype) -- todo: specification + if not busy then break end 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) + for k,v in next, expansions do + expansions[k] = gsub(v,"\\", '/') end end -function input.texdatablob(filename, filetype) - local ok, data, size = input.loadbinfile(filename, filetype) - return data or "" +function resolvers.variable(name) + return entry(instance.variables,name) 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 +function resolvers.expansion(name) + return entry(instance.expansions,name) end -function input.logmode() - return (os.getenv("MTX.LOG.MODE") or os.getenv("MTX_LOG_MODE") or "tex"):lower() +function resolvers.is_variable(name) + return is_entry(instance.variables,name) 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 +function resolvers.is_expansion(name) + return is_entry(instance.expansions,name) 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$") - ) +function resolvers.unexpanded_path_list(str) + local pth = resolvers.variable(str) + local lst = resolvers.split_path(pth) + return expanded_path_from_list(lst) end --- todo: describe which functions are public (maybe input.private. ... ) +function resolvers.unexpanded_path(str) + return file.join_path(resolvers.unexpanded_path_list(str)) +end --- beware: i need to check where we still need a / on windows: +do -- no longer needed -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 + local done = { } -function input.do_with_path(name,func) - for _, v in pairs(input.expanded_path_list(name)) do - func("^"..input.clean_path(v)) + 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 -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 + 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 - 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") + 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 - ---~ 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 = { } +end - 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 +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 - p = p .. "../" + break 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 + -- 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 - 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 + -- 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 - 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 - - -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-- -

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 structured file. Actually, any logging that -is hooked into callbacks will be \XML\ by default.

---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-- -

This looks pretty ugly but we need to speed things up a bit.

---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("%s",category,format(fmt,...))) -end -function logs.xml.line(fmt,...) -- new - write_nl(format("%s",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("") end end -function logs.xml.push () 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,...)) + return new + end end -function logs.tex.line(fmt,...) -- new - write_nl(format(fmt,...)) + +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 logs.set_level(level) - logs.level = logs.levels[level] or level +function resolvers.expand_path(str) + return file.join_path(resolvers.expanded_path_list(str)) 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]) +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 logs.xml.start_page_number() - write_nl(format("

") - write_nl("") +function resolvers.expand_path_from_var(str) + return file.join_path(resolvers.expanded_path_list_from_var(str)) end -function logs.xml.report_output_pages(p,b) - write_nl(format("", p)) - write_nl(format("", b)) - write_nl("") +function resolvers.format_of_var(str) + return formats[str] or formats[alternatives[str]] or '' end - -function logs.xml.report_output_log() +function resolvers.format_of_suffix(str) + return suffixmap[file.extname(str)] or 'tex' end -function input.logger(...) -- assumes test for input.trace > n - if input.trace > 0 then - logs.report(...) - end +function resolvers.variable_of_format(str) + return formats[str] or formats[alternatives[str]] or '' end -function input.report(fmt,...) - if input.verbose then - logs.report(input.banner or "report",format(fmt,...)) +function resolvers.var_of_format_or_suffix(str) + local v = formats[str] + if v then + return v end -end - -function input.reportlines(str) -- todo: - for line in str:gmatch("(.-)[\n\r]") do - logs.report(input.banner or "report",line) + v = formats[alternatives[str]] + if v then + return v + end + v = suffixmap[file.extname(str)] + if v then + return formats[isf] end + return '' end -input.moreinfo = [[ -more information about ConTeXt and the tools that come with it can be found at: +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 -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 -]] +resolvers.isreadable = { } -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) +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 -logs.set_level('error') -logs.set_method('tex') - - -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-- -

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.

- - -TEXMFCACHE=$TMP;$TEMP;$TMPDIR;$TEMPDIR;$HOME;$TEXMFVAR;$VARTEXMF;. - - -

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.

---ldx]]-- - -local format = string.format - -caches = caches or { } -dir = dir or { } -texmf = texmf or { } +resolvers.isreadable.tex = resolvers.isreadable.file -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" } +-- name +-- name/name -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 +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 - cachepath = nil + elseif trace_locating then + logs.report("fileio",'! blobpath no: %s (%s)',blobpath,bname) 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 + if #filelist > 0 then + return filelist + else + return nil end - return cachepath end -function caches.configpath() - return table.concat(input.instance.cnffiles,";") +function resolvers.suffix_of_format(str) + if suffixes[str] then + return suffixes[str][1] + else + return "" + end end -function caches.hashed(tree) - return md5.hex((tree:lower()):gsub("[\\\/]+","/")) +function resolvers.suffixes_of_format(str) + if suffixes[str] then + return suffixes[str] + else + return {} + end end ---~ tracing: +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 ---~ 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 +-- split the next one up for readability (bu this module needs a cleanup anyway) -function caches.treehash() - local tree = caches.configpath() - if not tree or tree == "" then - return false - else - return caches.hashed(tree) +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 -function caches.setpath(...) - if not caches.path then - if not caches.path then - caches.path = caches.temp() +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 - 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) + 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 - caches.path = dir.mkdirs(caches.path,caches.base,caches.more) + 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 - 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 + for k=1,#result do + result[k] = file.collapse_path(result[k]) end - caches.path = dir.expand_name(caches.path) - return caches.path -end - -function caches.definepath(category,subcategory) - return function() - return caches.setpath(category,subcategory) + if instance.remember then + instance.found[stamp] = result end + return result 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 +if not resolvers.concatinators then resolvers.concatinators = { } end -function caches.is_writable(filepath,filename) - local tmaname, tmcname = caches.setluanames(filepath,filename) - return file.is_writable(tmaname) -end +resolvers.concatinators.tex = file.join +resolvers.concatinators.file = resolvers.concatinators.tex -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 +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 - 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 + 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 - local cleanup = input.boolean_variable("PURGECACHE", false) - local strip = input.boolean_variable("LUACSTRIP", true) - utils.lua.compile(tmaname, tmcname, cleanup, strip) + instance.format = '' + return result 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") +function resolvers.find_file(filename,filetype,mustexist) + return (resolvers.find_files(filename,filetype,mustexist)[1] or "") end ---[[ldx-- -

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).

- -

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.

- -

Examples of usage can be found in the font related code.

---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 +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 - 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) + 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 - 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 + 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 - report(container,"stored",name) - container.storage[name] = data end - return data - end - - function containers.content(container,name) - return container.storage[name] end - + return result 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) +function resolvers.find_given_file(filename) + return (resolvers.find_given_files(filename)[1] or "") 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)) +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 - if not filename or (filename == "") then - filename = dataname + 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 - return file.join(pathname,filename) end - end) + end + return done 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") } +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 - 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 + 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 - f:close() end end - input.stoptiming(input.instance) + 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 --- store info in format +function resolvers.find_wildcard_file(filename) + return (resolvers.find_wildcard_files(filename)[1] or "") +end -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) +-- main user functions -function input.storage.register(...) - input.storage.data[#input.storage.data+1] = { ... } +function resolvers.automount() + -- implemented later end -function input.storage.evaluate(name) - input.storage.evaluators[#input.storage.evaluators+1] = name +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.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 +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 - 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 + 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 - name = str + for _,v in ipairs(result) do + report(v) + end 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 +-- strtab --- 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 +resolvers.var_value = resolvers.variable -- output the value of variable $STRING. +resolvers.expand_var = resolvers.expansion -- output variable expansion of STRING. -if zip and input then - zip.supported = true -else - zip = { } - zip.supported = false +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 -if not zip.supported then +-- resolvers.find_file(filename) +-- resolvers.find_file(filename, filetype, mustexist) +-- resolvers.find_file(filename, mustexist) +-- resolvers.find_file(filename, filetype) - 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 +function resolvers.register_file(files, name, path) + if files[name] then + if type(files[name]) == 'string' then + files[name] = { files[name], path } else - return str + files[name] = path end + else + files[name] = path 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 +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 zip.closearchive(name) - if not name or name == "" and zip.archives[name] then - zip.close(zip.archives[name]) - zip.archives[name] = nil - 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 - -- 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 +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 input.hashers.zip(tag,name) - input.report("loading zip file %s as %s",name,tag) - input.usezipfile(tag .."?tree=" .. name) +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 input.concatinators.zip(tag,path,name) - if not path or path == "" then - return tag .. '?name=' .. name - else - return tag .. '?name=' .. path .. "/" .. name - 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 input.is_readable.zip(name) - return true - end +function resolvers.do_with_var(name,func) + func(expanded_var(name)) +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) +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 - 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) + 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 - 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 +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) +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 - return unpack(input.openers.notfound) end + return nil, nil +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) +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 - -- zip:///somefile.zip - -- zip:///somefile.zip?tree=texmf-local -> mount +texconfig.kpse_init = false - 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 +kpse = { original = kpse } setmetatable(kpse, { __index = function(k,v) return resolvers[v] 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 +-- for a while -end +input = resolvers --- 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 +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" +} -if not versions then versions = { } end versions['luat-tex'] = 1.001 +--[[ldx-- +

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.

--- special functions that deal with io + +TEXMFCACHE=$TMP;$TEMP;$TMPDIR;$TEMPDIR;$HOME;$TEXMFVAR;$VARTEXMF;. + -local format = string.format +

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.

+--ldx]]-- -if texconfig and not texlua then +local format, lower, gsub = string.format, string.lower, string.gsub - input.level = input.level or 0 +local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end) - if input.logmode() == 'xml' then - function input.show_open(name) - input.level = input.level + 1 - texio.write_nl("") - end - function input.show_close(name) - texio.write(" ") - input.level = input.level - 1 - end - function input.show_load(name) - texio.write_nl("") -- level? - end - else - function input.show_open () end - function input.show_close() end - function input.show_load () end - end +caches = caches or { } - 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 +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" } - input.filters.dynamic_translator = nil - input.filters.frozen_translator = nil - input.filters.utf_translator = nil +function caches.cleanname(name) + return (gsub(lower(name),"[^%w%d]+","-")) +end - 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 +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 - } - else - if input.trace > 0 then - input.logger('+ opener: %s, file: %s',tag,filename) + cachepath = nil 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) - 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 + 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 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) +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 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 - end - end +function caches.setpath(...) + if not caches.path then + if not caches.path then + caches.path = caches.temp() end - if input.trace > 0 then - input.logger('- loader: %s, file: %s',tag,filename) + 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 - 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) + if not caches.path then + caches.path = '.' end - function input.loaders.tex(filename) - return input.loaders.generic('tex',filename) + 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 --- 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 ... +function caches.definepath(category,subcategory) + return function() + return caches.setpath(category,subcategory) + end +end - ctx = ctx or { } +function caches.setluanames(path,name) + return path .. "/" .. name .. ".tma", path .. "/" .. name .. ".tmc" +end - 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 +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 - -- this will become: ctx.install_statistics(fnc() return ..,.. end) etc - - local statusinfo, n = { }, 0 +--~ function caches.loaddata(path,name) +--~ local tmaname, tmcname = caches.setluanames(path,name) +--~ return dofile(tmcname) or dofile(tmaname) +--~ end - function ctx.register_statistics(tag,pattern,fnc) - statusinfo[#statusinfo+1] = { tag, pattern, fnc } - if #tag > n then n = #tag end - end +function caches.iswritable(filepath,filename) + local tmaname, tmcname = caches.setluanames(filepath,filename) + return file.iswritable(tmaname) +end - function ctx.memused() - -- collectgarbage("collect") - return string.format("%s MB (ctx: %s MB)",math.round(collectgarbage("count")), math.round(status.luastate_bytes/1000)) +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 - - 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") + 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 -end end - -if texconfig and not texlua then - - texconfig.kpse_init = false - texconfig.trace_file_names = input.logmode() == 'tex' - texconfig.max_print_line = 100000 +-- here we use the cache for format loading (texconfig.[formatname|jobname]) - -- if still present, we overload kpse (put it off-line so to say) +--~ 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 - input.starttiming(input.instance) - if not input.instance then +end -- of closure - if not input.instance then -- prevent a second loading +do -- create closure to overcome 200 locals limit - input.instance = input.reset() - input.instance.progname = 'context' - input.instance.engine = 'luatex' - input.instance.validfile = input.validctxfile +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" +} - input.load() +resolvers.finders = resolvers.finders or { } +resolvers.openers = resolvers.openers or { } +resolvers.loaders = resolvers.loaders or { } - end +resolvers.finders.notfound = { nil } +resolvers.openers.notfound = { nil } +resolvers.loaders.notfound = { false, nil, 0 } - 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) +end -- of closure - 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 +do -- create closure to overcome 200 locals limit - if input.aleph_mode == nil then environment.aleph_mode = true end -- some day we will drop omega font support +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" +} - 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 +outputs = outputs or { } - 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("callback "..k.." is not set") end - end - end +end -- of closure - if callback then +do -- create closure to overcome 200 locals limit - input.start_actions = { } - input.stop_actions = { } +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" +} - 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 +local format, lower, gsub = string.format, string.lower, string.gsub - --~ 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) +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) - end +--[[ldx-- +

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).

- if callback then +

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.

- if input.logmode() == 'xml' then +

Examples of usage can be found in the font related code.

+--ldx]]-- - function input.start_page_number() - texio.write_nl("

") - texio.write_nl("") - end +containers = containers or { } - callback.register('start_page_number' , input.start_page_number) - callback.register('stop_page_number' , input.stop_page_number ) +containers.usecache = true - function input.report_output_pages(p,b) - texio.write_nl(""..p.."") - texio.write_nl(""..b.."") - texio.write_nl("") - end - function input.report_output_log() - 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 - callback.register('report_output_pages', input.report_output_pages) - callback.register('report_output_log' , input.report_output_log ) +local allocated = { } - function input.start_run() - texio.write_nl("") - texio.write_nl("") - texio.write_nl("") - end - function input.stop_run() - texio.write_nl("") - end - function input.show_statistics() - for k,v in pairs(status.list()) do - texio.write_nl("log",""..tostring(v).."") - end - end +-- tracing - table.insert(input.start_actions, input.start_run) - table.insert(input.stop_actions , input.show_statistics) - table.insert(input.stop_actions , input.stop_run) +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 - else - table.insert(input.stop_actions , input.show_statistics) - end +function containers.is_usable(container, name) + return container.enabled and caches and caches.iswritable(container.path, name) +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) +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 - if kpse then - - function kpse.find_file(filename,filetype,mustexist) - return input.find_file(filename,filetype,mustexist) +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 - 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 - + report(container,"stored",name) + container.storage[name] = data end + return data +end +function containers.content(container,name) + return container.storage[name] end --- program specific configuration (memory settings and alike) -if texconfig and not texlua then +end -- of closure - luatex = luatex or { } +do -- create closure to overcome 200 locals limit - 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' - } +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" +} - 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 +local format, lower, gsub = string.format, string.lower, string.gsub - function luatex.setvariables(tab) - for k,v in pairs(luatex.variables()) do - tab[k] = v - end - 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) - if not luatex.variables_set then - luatex.setvariables(texconfig) - luatex.variables_set = true - end +-- since we want to use the cache instead of the tree, we will now +-- reimplement the saver. - texconfig.max_print_line = 100000 - texconfig.max_in_open = 127 +local save_data = resolvers.save_data +local load_data = resolvers.load_data -end +resolvers.cachepath = nil -- public, for tracing +resolvers.usecache = true -- public, for tracing --- some tex basics, maybe this will move to ctx +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 -if tex then +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 - local texsprint, texwrite = tex.sprint, tex.write +-- we will make a better format, maybe something xml or just text or lua - if not cs then cs = { } end +resolvers.automounted = resolvers.automounted or { } - function cs.def(k,v) - texsprint(tex.texcatcodes, "\\def\\" .. k .. "{" .. v .. "}") +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 - - function cs.chardef(k,v) - texsprint(tex.texcatcodes, "\\chardef\\" .. k .. "=" .. v .. "\\relax") + 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 cs.boolcase(b) - if b then texwrite(1) else texwrite(0) 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 cs.testcase(b) - if b then - texsprint(tex.texcatcodes, "\\firstoftwoarguments") +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 - texsprint(tex.texcatcodes, "\\secondoftwoarguments") + 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", @@ -6522,90 +6348,218 @@ $SELFAUTODIR : /usr/tex/bin $SELFAUTOPARENT : /usr/tex -

How about just forgetting abou them?

+

How about just forgetting about them?

--ldx]]-- -input = input or { } -input.suffixes = input.suffixes or { } -input.formats = input.formats or { } - -input.suffixes['gf'] = { 'gf' } -input.suffixes['pk'] = { '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'] = { } +local suffixes = resolvers.suffixes +local formats = resolvers.formats + +suffixes['gf'] = { 'gf' } +suffixes['pk'] = { '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--

If you wondered abou tsome of the previous mappings, how about the next bunch:

--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' +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 @@ -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["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 environment.arguments["trace"] then resolvers.settrace(environment.arguments["trace"]) end -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 .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]))) - 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 + logs.simple("using format name: %s",fmtname) + logs.simple("no luc/lua with name: %s",barename) 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("\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("^ 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- 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("( 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%s%s%s%s%s",id,id,name,file,sub,type) + end + end + listoffonts[#listoffonts+1] = "" + return concat(listoffonts,"\n") + end + end + return "no fonts" +end + +local edit_template = [[ + +

name:    title:  +

scripts: %s +

languages: %s +

features: %s +

options: %s +]] + +local result_template = [[ +

+ +

results: + tex file + pdf file +

+]] + +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(" %s",s,v,v,v,v) + else + scripts[#scripts+1] = format(" %s",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(" %s",l,v,v,v,v) + else + languages[#languages+1] = format(" %s",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(" %s",f,v,v,v,v) + else + features[#features+1] = format(" %s",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(" %s",v,v,v) + else + options[#options+1] = format(" %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 = [[ +

+%s
+
+]] + +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("

names

",what) + result[#result+1] = "" + result[#result+1] = format("",currentfont) + result[#result+1] = format("",fontname) + result[#result+1] = format("",fontfile) + result[#result+1] = "
fontname:%s
fullname:%s
filename:%s
" + 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("

%s features

",what) + result[#result+1] = "" + result[#result+1] = "" + 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("",title,f,s,concat(table.sortedkeys(ss)," ")) + end + end + result[#result+1] = "
featuretag script languages 
%s  %s  %s  %s  
" + end + end + else + result[#result+1] = "

This font has no features." + end + return concat(result,"\n") +end + + +local info_template = [[ +

+version   : %s
+comment   : %s
+author    : %s
+copyright : %s
+
+maillist  : ntg-context at ntg.nl
+webpage   : www.pragma-ade.nl
+wiki      : contextgarden.net
+
+]] + +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: +

+ + + + + + + + + +
name  %s
title  %s
font  %s
script  %s
language  %s
features  %s
options  %s
sampletext %s
+]] + +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("del name font fontname script language features title sampletext ") + for k,v in table.sortedpairs(storage) do + local fontname, fontfile, issub = fonts.names.specification(v.font or "") + result[#result+1] = format("x %s %s %s %s %s %s %s %s ", + 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("%s
",concat(result,"\n")) + end +end + +local function reset_font(currentfont) + return edit_font(currentfont) +end + +local extras_template = [[ + remake font database (take some time)

+]] + +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 = [[ + +]] + +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("",v,v) + end + lmx.set('menu', concat(menu," ")) + + 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 = "
%s
" +} + +document.setups.span = { + pe = "%s" +} + +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 = [[%s]], + href = [[%s]], + source = [[%s]], + optional_single = "[optional string %s]", + optional_list = "[optional list %s]", + mandate_single = "[mandate string %s]", + mandate_list = "[mandate list %s]", + parameter = [[%s%s%s]], + parameters = [[%s
]], + listing = [[
%s]],
+    special = "%s",
+    default = "%s",
+}
+
+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("
") then + parameters[#parameters+1] = formats.parameter:format("
","","") + 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("
","","") + 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,"
") + local i = concat(ints,"

") + + 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("%s

",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("%s %s

%s %s

",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 = [[ +

%s (red) %s (blue)

+ + + + + +
%s +   min: %s
+   max: %s
+   pages: %s
+   average: %s
+
+
+]] + +local html_menu = [[ + %s +]] + +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, "  ")) + lmx.set('nodesmenu', concat(htmldata.nodes, "  ")) + 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//", "texmf-context" }, + { "context/img/", "texmf-context" }, + { "misc/setuptex/", "." }, + { "misc/web2c", "texmf" }, + { "bin/common//", "texmf-" }, + { "bin/context//", "texmf-" }, + { "bin/metapost//", "texmf-" }, + { "bin/man/", "texmf-" }, +} + +-- 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//", "texmf-context" }, - { "context/img/", "texmf-context" }, - { "context/config/", "texmf-context" }, - { "misc/setuptex/", "." }, - { "misc/web2c", "texmf" }, - { "bin/common//", "texmf-" }, - { "bin/context//", "texmf-" }, - { "bin/metapost//", "texmf-" }, { "bin/luatex//", "texmf-" }, - { "bin/man/", "texmf-" } }, ["xetex"] = { - { "base/tex/", "texmf" }, - { "base/metapost/", "texmf" }, { "base/xetex/", "texmf" }, { "fonts/new/", "texmf" }, - { "fonts/common/", "texmf" }, - { "fonts/other/", "texmf" }, - { "context//", "texmf-context" }, - { "context/img/", "texmf-context" }, - { "context/config/", "texmf-context" }, - { "misc/setuptex/", "." }, - { "misc/web2c", "texmf" }, - { "bin/common//", "texmf-" }, - { "bin/context//", "texmf-" }, - { "bin/metapost//", "texmf-" }, { "bin/xetex//", "texmf-" }, - { "bin/man/", "texmf-" } }, ["pdftex"] = { - { "base/tex/", "texmf" }, - { "base/metapost/", "texmf" }, { "fonts/old/", "texmf" }, - { "fonts/common/", "texmf" }, - { "fonts/other/", "texmf" }, - { "context//", "texmf-context" }, - { "context/img/", "texmf-context" }, - { "context/config/", "texmf-context" }, - { "misc/setuptex/", "." }, - { "misc/web2c", "texmf" }, - { "bin/common//", "texmf-" }, - { "bin/context//", "texmf-" }, - { "bin/metapost//", "texmf-" }, { "bin/pdftex//", "texmf-" }, - { "bin/man/", "texmf-" } }, ["all"] = { - { "base/tex/", "texmf" }, - { "base/metapost/", "texmf" }, - { "base/xetex/", "texmf" }, - { "fonts/old/", "texmf" }, { "fonts/new/", "texmf" }, - { "fonts/common/", "texmf" }, - { "fonts/other/", "texmf" }, - { "context//", "texmf-context" }, - { "context/img/", "texmf-context" }, - { "context/config/", "texmf-context" }, - { "misc/setuptex/", "." }, - { "misc/web2c", "texmf" }, - { "bin/common//", "texmf-" }, - { "bin/context//", "texmf-" }, - { "bin/metapost//", "texmf-" }, + { "fonts/old/", "texmf" }, + { "base/xetex/", "texmf" }, { "bin/luatex//", "texmf-" }, { "bin/xetex//", "texmf-" }, { "bin/pdftex//", "texmf-" }, - { "bin/man/", "texmf-" } }, } 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) + archive = archive:gsub("", 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) - local destination = string.format("%s/%s", texroot, collection[2]:gsub("", platform)) - destination = destination:gsub("\\","/") - archive = archive:gsub("",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) + local destination = format("%s/%s", texroot, c[2]:gsub("", platform)) + destination = destination:gsub("\\","/") + archive = archive:gsub("",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 + +--~ 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" +} -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 : @@ -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 + +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 --- 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 +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 = 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 + + +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" +} -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 = "\\", ";" @@ -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 - + 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 -- of closure -end end +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" +} --- 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 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 -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'} @@ -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 --- 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 +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" +} -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 @@ -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 -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 @@ -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 + +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-xml'] = { +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 + +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 --- some code may move to l-xmlext +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--

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 based one. The find based parser can be found in l-xml-edu.lua along with other older code.

@@ -2267,17 +2608,30 @@ optimize the code.

--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-- +

This module can be used stand alone but also inside in +which case it hooks into the tracker code. Therefore we provide a few +functions that set the tracers.

+--ldx]]-- ---~ local pairs, next, type = pairs, next, type +local trace_remap = false + +if trackers then + trackers.register("xml.remap", function(v) trace_remap = v end) +end --- todo: some things per xml file, like namespace remapping +function xml.settrace(str,value) + if str == "remap" then + trace_remap = value or false + end +end --[[ldx--

First a hack to enable namespace resolving. A namespace is characterized by @@ -2289,64 +2643,60 @@ much cleaner.

xml.xmlns = xml.xmlns or { } -do +local check = lpeg.P(false) +local parse = check - local check = lpeg.P(false) - local parse = check - - --[[ldx-- -

The next function associates a namespace prefix with an . This - normally happens independent of parsing.

+--[[ldx-- +

The next function associates a namespace prefix with an . This +normally happens independent of parsing.

- - xml.registerns("mml","mathml") - - --ldx]]-- + +xml.registerns("mml","mathml") + +--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-- -

The next function also registers a namespace, but this time we map a - given namespace prefix onto a registered one, using the given - . This used for attributes like xmlns:m.

+--[[ldx-- +

The next function also registers a namespace, but this time we map a +given namespace prefix onto a registered one, using the given +. This used for attributes like xmlns:m.

- - xml.checkns("m","http://www.w3.org/mathml") - - --ldx]]-- + +xml.checkns("m","http://www.w3.org/mathml") + +--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-- -

Next we provide a way to turn an into a registered - namespace. This used for the xmlns attribute.

- - - resolvedns = xml.resolvens("http://www.w3.org/mathml") - - - This returns mml. - --ldx]]-- +--[[ldx-- +

Next we provide a way to turn an into a registered +namespace. This used for the xmlns attribute.

- function xml.resolvens(url) - return parse:match(url:lower()) or "" - end + +resolvedns = xml.resolvens("http://www.w3.org/mathml") + - --[[ldx-- -

A namespace in an element can be remapped onto the registered - one efficiently by using the xml.xmlns table.

- --ldx]]-- +This returns mml. +--ldx]]-- +function xml.resolvens(url) + return parse:match(lower(url)) or "" end +--[[ldx-- +

A namespace in an element can be remapped onto the registered +one efficiently by using the xml.xmlns table.

+--ldx]]-- + --[[ldx--

This version uses . 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 @@ -2382,247 +2732,253 @@ element.

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(" 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-- -

Packaging data in an xml like table is done with the following - function. Maybe it will go away (when not used).

- --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("Packaging data in an xml like table is done with the following +function. Maybe it will go away (when not used).

+--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 - xml.error_handler = (logs and logs.report) or (input and input.report) or print +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--

We cannot load an 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!

--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--

In 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.

--ldx]]-- -do - - -- todo: add 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 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("",edt[1])) - handle("") - elseif etg == "@cm@" then - -- handle(format("",edt[1])) - handle("") - elseif etg == "@cd@" then - -- handle(format("",edt[1])) - handle("") - elseif etg == "@dt@" then - -- handle(format("",edt[1])) - handle("") - 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("",edt[1])) + handle("") + elseif etg == "@cm@" then + -- handle(format("",edt[1])) + handle("") + elseif etg == "@cd@" then + -- handle(format("",edt[1])) + handle("") + elseif etg == "@dt@" then + -- handle(format("",edt[1])) + handle("") + 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("",ens,etg)) - handle("") - 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("",ens,etg)) + handle("") 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("",etg)) - handle("") - 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("",etg)) + handle("") + 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-- -

At the cost of some 25% runtime overhead you can first convert the tree to a string - and then handle the lot.

- --ldx]]-- +--[[ldx-- +

At the cost of some 25% runtime overhead you can first convert the tree to a string +and then handle the lot.

+--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-- +

This module can be used stand alone but also inside 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.

+--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--

We've now arrived at an intersting part: accessing the tree using a subset of and since we're not compatible we call it . We will explain more about its usage in other documents.

--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("\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("\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.

--ldx]]-- -do - - 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 +local functions = xml.functions +local expressions = xml.expressions - 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.contains = string.find +expressions.find = string.find +expressions.upper = string.upper +expressions.lower = string.lower +expressions.number = tonumber +expressions.boolean = toboolean - 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--

Next come all kind of locators and manipulators. The most generic function here is xml.filter(root,pattern). All registers functions in the filters namespace @@ -3779,399 +4163,414 @@ local r, d, k = xml.filter(root,"/a/b/c/position(4)" --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 - 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[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 +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.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-- -

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.

- --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 +end - -- todo: also hash, could be gc'd +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.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-- -

The following functions collect elements and texts.

- --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.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.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 +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 - --[[ldx-- -

Often using an iterators looks nicer in the code than passing handler - functions. The book describes how to use coroutines for that - purpose (). This permits - code like:

+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 - - for r, d, k in xml.elements(xml.load('text.xml'),"title") do - print(d[k]) - 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 -

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:

+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.first(root,pattern) - for rt,dt,dk in xml.elements(root,pattern) +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 - return nil, nil, nil, nil end - - -

We use the function variants in the filters.

- --ldx]]-- + return nil, nil, nil, nil +end - local wrap, yield = coroutine.wrap, coroutine.yield +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.elements(root,pattern,reverse) - return wrap(function() traverse(root, lpath(pattern), yield, reverse) 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.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.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-- +

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.

+--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 - 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 +-- 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 - 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 +--~ 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-- +

The following functions collect elements and texts.

+--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 + end + end) + return dd, rr +end - function xml.process_attributes(root, pattern, handle) - traverse(root, lpath(pattern), function(r,d,k) +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 a = ek.at or { } - handle(a) - if next(a) then -- next is faster than type (and >0 test) - ek.at = a + 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 - ek.at = nil + t[#t+1] = tx or "" end - 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-- +

Often using an iterators looks nicer in the code than passing handler +functions. The book describes how to use coroutines for that +purpose (). This permits +code like:

+ + +for r, d, k in xml.elements(xml.load('text.xml'),"title") do + print(d[k]) +end + + +

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:

+ + +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 + + +

We use the function variants in the filters.

+--ldx]]-- - --[[ldx-- -

We've now arrives at the functions that manipulate the tree.

- --ldx]]-- +local wrap, yield = coroutine.wrap, coroutine.yield - 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) +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 - 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 + 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-- +

We've now arrives at the functions that manipulate the tree.

+--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 - 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.

--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 = { ['&'] = '&', ['<'] = '<', ['>'] = '>', ['"'] = '"' } --~ 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 - - -- 10 * 1000 * "oeps< oeps> oeps& asfjhalskfjh alskfjh alskfjh alskfjh ;al J;LSFDJ" - -- - -- 1559:0257:0288:0190 (last one suggested by roberto) +-- 100 * 2500 * "oeps< oeps> oeps&" : gsub:lpeg|lpeg|lpeg +-- +-- 1021:0335:0287:0247 - -- escaped = Cs((S("<&>") / xml.escapes + 1)^0) - -- escaped = Cs((S("<")/"<" + S(">")/">" + S("&")/"&" + 1)^0) - local normal = (1 - S("<&>"))^0 - local special = P("<")/"<" + P(">")/">" + P("&")/"&" - local escaped = Cs(normal * (special * normal)^0) +-- 10 * 1000 * "oeps< oeps> oeps& asfjhalskfjh alskfjh alskfjh alskfjh ;al J;LSFDJ" +-- +-- 1559:0257:0288:0190 (last one suggested by roberto) - -- 100 * 1000 * "oeps< oeps> oeps&" : gsub:lpeg == 0153:0280:0151:0080 (last one by roberto) +-- escaped = Cs((S("<&>") / xml.escapes + 1)^0) +-- escaped = Cs((S("<")/"<" + S(">")/">" + S("&")/"&" + 1)^0) +local normal = (1 - S("<&>"))^0 +local special = P("<")/"<" + P(">")/">" + P("&")/"&" +local escaped = Cs(normal * (special * normal)^0) - -- unescaped = Cs((S("<")/"<" + S(">")/">" + S("&")/"&" + 1)^0) - -- unescaped = Cs((((P("&")/"") * (P("lt")/"<" + P("gt")/">" + P("amp")/"&") * (P(";")/"")) + 1)^0) - local normal = (1 - S"&")^0 - local special = P("<")/"<" + P(">")/">" + P("&")/"&" - local unescaped = Cs(normal * (special * normal)^0) +-- 100 * 1000 * "oeps< oeps> oeps&" : gsub:lpeg == 0153:0280:0151:0080 (last one by roberto) - -- 100 * 5000 * "oeps oeps oeps " : gsub:lpeg == 623:501 msec (short tags, less difference) +-- unescaped = Cs((S("<")/"<" + S(">")/">" + S("&")/"&" + 1)^0) +-- unescaped = Cs((((P("&")/"") * (P("lt")/"<" + P("gt")/">" + P("amp")/"&") * (P(";")/"")) + 1)^0) +local normal = (1 - S"&")^0 +local special = P("<")/"<" + P(">")/">" + P("&")/"&" +local unescaped = Cs(normal * (special * normal)^0) - local cleansed = Cs(((P("<") * (1-P(">"))^0 * P(">"))/"" + 1)^0) +-- 100 * 5000 * "oeps oeps oeps " : gsub:lpeg == 623:501 msec (short tags, less difference) - 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 +local cleansed = Cs(((P("<") * (1-P(">"))^0 * P(">"))/"" + 1)^0) -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,155 +4868,46 @@ function xml.join(t,separator,lastseparator) end end +function xml.statistics() + return { + lpathcalls = lpathcalls, + lpathcached = lpathcached, + } +end ---[[ldx-- -

We provide (at least here) two entity handlers. The more extensive -resolver consults a hash first, tries to convert to next, -and finaly calls a handler when defines. When this all fails, the -original entity is returned.

---ldx]]-- +-- xml.set_text_cleanup(xml.show_text_entities) +-- xml.set_text_cleanup(xml.resolve_text_entities) -do if unicode and unicode.utf8 then +--~ xml.lshow("/../../../a/(b|c)[@d='e']/f") +--~ xml.lshow("/../../../a/!(b|c)[@d='e']/f") +--~ xml.lshow("/../../../a/!b[@d!='e']/f") - xml.entities = xml.entities or { } -- xml.entity_handler == function +--~ x = xml.convert([[ +--~ +--~ 01 +--~ 02 +--~ 03 +--~ OK +--~ 05 +--~ 06 +--~ ALSO OK +--~ +--~ ]]) - function xml.entity_handler(e) - return format("[%s]",e) - end +--~ xml.settrace("lpath",true) - local char = unicode.utf8.char +--~ 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')]")) - 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, - 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([[ ---~ ---~ 01 ---~ 02 ---~ 03 ---~ OK ---~ 05 ---~ 06 ---~ ALSO OK ---~ ---~ ]]) - ---~ xml.trace_lpath = true - ---~ xml.xshow(xml.first(x,"b[position() > 2 and position() < 5 and text() == 'ok']")) ---~ xml.xshow(xml.first(x,"b[position() > 2 and position() < 5 and text() == upper('ok')]")) ---~ xml.xshow(xml.first(x,"b[@n=='03' or @n=='08']")) ---~ xml.xshow(xml.all (x,"b[number(@n)>2 and number(@n)<6]")) ---~ xml.xshow(xml.first(x,"b[find(text(),'ALSO')]")) - ---~ str = [[ ---~ ---~ ---~ my secret ---~ ---~ ]] +--~ str = [[ +--~ +--~ +--~ my secret +--~ +--~ ]] --~ x = xml.convert([[ --~ 0102xx03OK @@ -4633,177 +4921,522 @@ 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" -end +--[[ldx-- +

We provide (at least here) two entity handlers. The more extensive +resolver consults a hash first, tries to convert to next, +and finaly calls a handler when defines. When this all fails, the +original entity is returned.

+--ldx]]-- -function utils.report(...) - print(...) -end +xml.entities = xml.entities or { } -- xml.entity_handler == function -utils.merger.strip_comment = true +function xml.entity_handler(e) + return format("[%s]",e) +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() - 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 "" +local function toutf(s) + return utfchar(tonumber(s,16)) 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() +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_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)) +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 - return "" + 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 -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 +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 - utils.report("no library %s",name) + resolve_entities(dk) end end 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) - ) - ) +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 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 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 utils.merger.selfclean(name) - utils.merger._self_save_( - name, - utils.merger._self_swap_( - utils.merger._self_load_(name), - "" - ) - ) +function xml.show_text_entities(str) + if find(str,"&") then + return (gsub(str,"&(.-);","[%1]")) + else + return str + end 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) +-- 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 - return done end +end -- of closure -if not modules then modules = { } end modules ['luat-lib'] = { +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", - 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 +local concat = table.concat +local type, next, tonumber, tostring, setmetatable, loadstring = type, next, tonumber, tostring, setmetatable, loadstring +local format, gsub = string.format, string.gsub -os.setlocale(nil,nil) -- useless feature and even dangerous in luatex +--[[ldx-- +

The following helper functions best belong to the lmxl-ini +module. Some are here because we need then in the mk +document and other manuals, others came up when playing with +this module. Since this module is also used in we've +put them here instead of loading mode modules there then needed.

+--ldx]]-- -function os.setlocale() - -- no way you can mess with it +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 -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 +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 -environment = environment or { } -environment.arguments = { } -environment.files = { } -environment.sortedflags = nil +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 -function environment.initialize_arguments(arg) - local arguments, files = { }, { } - environment.arguments, environment.files, environment.sortedflags = arguments, files, nil - for index, argument in pairs(arg) do +--~ xml.escapes = { ['&'] = '&', ['<'] = '<', ['>'] = '>', ['"'] = '"' } +--~ 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("<")/"<" + S(">")/">" + S("&")/"&" + 1)^0) +local normal = (1 - S("<&>"))^0 +local special = P("<")/"<" + P(">")/">" + P("&")/"&" +local escaped = Cs(normal * (special * normal)^0) + +-- 100 * 1000 * "oeps< oeps> oeps&" : gsub:lpeg == 0153:0280:0151:0080 (last one by roberto) + +-- unescaped = Cs((S("<")/"<" + S(">")/">" + S("&")/"&" + 1)^0) +-- unescaped = Cs((((P("&")/"") * (P("lt")/"<" + P("gt")/">" + P("amp")/"&") * (P(";")/"")) + 1)^0) +local normal = (1 - S"&")^0 +local special = P("<")/"<" + P(">")/">" + P("&")/"&" +local unescaped = Cs(normal * (special * normal)^0) + +-- 100 * 5000 * "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 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 '' + 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 @@ -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,279 +5556,163 @@ if arg then end +-- weird place ... depends on a not yet loaded module -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 +function environment.texfile(filename) + return resolvers.find_file(filename,'tex') +end --- 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. +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 --- 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. +environment.loadedluacode = loadfile -- can be overloaded --- Beware, loading and saving is overloaded in luat-tmp! +--~ 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 -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' } +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 --- here we catch a few new thingies (todo: add these paths to context.tmf) --- --- FONTFEATURES = .;$TEXMF/fonts/fea// --- FONTCIDMAPS = .;$TEXMF/fonts/cid// +-- the next ones can use the previous ones / combine -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? +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 - 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 + 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 - 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") + return false end --- backward compatible ones -input.alternatives = { } +end -- of closure -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' +do -- create closure to overcome 200 locals limit --- obscure ones +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" +} -input.formats ['misc fonts'] = '' -input.suffixes['misc fonts'] = { } +local format = string.format -input.formats ['sfd'] = 'SFDFONTS' -input.suffixes ['sfd'] = { 'sfd' } -input.alternatives['subfont definition files'] = 'sfd' +local statusinfo, n, registered = { }, 0, { } --- 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. +statistics = statistics or { } -function input.newinstance() +statistics.enable = true +statistics.threshold = 0.05 - local instance = { } +-- timing functions - 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 +local clock = os.gettimeofday or os.clock - -- store once, freeze and faster (once reset we can best use instance.environment) +function statistics.hastimer(instance) + return instance and instance.starttime +end - 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 statistics.starttiming(instance) + if instance then + local it = instance.timing + if not it then + it = 0 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.starttiming(instance) - if instance then + 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 +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() @@ -5230,2170 +5720,2434 @@ do instance.stoptime = stoptime instance.loadtime = instance.loadtime + loadtime if report then - input.report("load time %0.3f",loadtime) + statistics.report("load time %0.3f",loadtime) end + instance.timing = 0 return loadtime end end - return 0 end - + return 0 end -function input.elapsedtime(instance) +function statistics.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 +function statistics.elapsedindeed(instance) + local t = (instance and instance.loadtime) or 0 + return t > statistics.threshold end -input.loadtime = input.elapsedtime +-- general function -function input.env(key) - return input.instance.environment[key] or input.osenv(key) +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 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) +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 - ie[key] = value + statistics.enable = false 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) +function statistics.show_job_stat(tag,data,n) + texio.write_nl(format("%-15s: %s - %s","mkiv lua stats",tag:rpadd(n," "),data)) +end -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 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 -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 +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 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 +function statistics.runtime() + statistics.stoptiming(statistics) + return statistics.formatruntime(statistics.elapsedtime(statistics)) 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 +function statistics.formatruntime(runtime) + return format("%s seconds", statistics.elapsedtime(statistics)) 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() +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-- +

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 structured file. Actually, any logging that +is hooked into callbacks will be \XML\ by default.

+--ldx]]-- + +logs = logs or { } +logs.xml = logs.xml or { } +logs.tex = logs.tex or { } + +--[[ldx-- +

This looks pretty ugly but we need to speed things up a bit.

+--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 - input.checkconfigdata() end -function input.load_lua() - local instance = input.instance - if #instance.luafiles == 0 then - -- yet harmless +-- tex logging + +function logs.tex.report(category,fmt,...) -- new + if fmt then + write_nl(category .. " | " .. format(fmt,...)) 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() + write_nl(category .. " |") 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 +function logs.tex.line(fmt,...) -- new + if fmt then + write_nl(format(fmt,...)) + else + write_nl("") 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 +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 - f:close() else - input.report("skipping %s", fname) + write(format("[%s",real)) end + else + write("[-") end end --- database loading +function logs.tex.stop_page_number() + write("]") +end -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 +logs.tex.report_job_stat = statistics.show_job_stat + +-- xml logging + +function logs.xml.report(category,fmt,...) -- new + if fmt then + write_nl(format("%s",category,format(fmt,...))) else - input.loadlists() - if instance.renewcache then - input.savefiles() - end + write_nl(format("",category)) end end - -function input.aux.append_hash(type,tag,name) - if input.trace > 0 then - input.logger("= hash append: %s",tag) +function logs.xml.line(fmt,...) -- new + if fmt then + write_nl(format("%s",format(fmt,...))) + else + write_nl("") 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 } ) +function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end +function logs.xml.stop () if logs.level > 0 then tw("") end end +function logs.xml.push () if logs.level > 0 then tw("" ) end end + +function logs.xml.start_run() + write_nl("") + write_nl("") -- xmlns='www.pragma-ade.com/luatex/schemas/context-job.rng' + write_nl("") 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() +function logs.xml.stop_run() + write_nl("") end --- locators +function logs.xml.start_page_number() + write_nl(format("

") + write_nl("") +end + +function logs.xml.report_output_pages(p,b) + write_nl(format("", p)) + write_nl(format("", b)) + write_nl("") +end + +function logs.xml.report_output_log() end -function input.locatedatabase(specification) - return input.methodhandler('locators', specification) +function logs.xml.report_tex_stat(k,v) + texiowrite_nl("log",""..tostring(v).."") 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) +local level = 0 + +function logs.xml.show_open(name) + level = level + 1 + texiowrite_nl(format("",level,name)) +end + +function logs.xml.show_close(name) + texiowrite(" ") + level = level - 1 +end + +function logs.xml.show_load(name) + texiowrite_nl(format("",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 --- hashers +local function simple(fmt,...) + if fmt then + write_nl(format("%s | %s",name,format(fmt,...))) + else + write_nl(format("%s |",name)) + end +end -function input.hashdatabase(tag,name) - return input.methodhandler('hashers',tag,name) +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 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 +function logs.setverbose(what) + if what then + trackers.enable("resolvers.verbose") + else + trackers.disable("resolvers.verbose") end + logs.verbose = what or false end -function input.hashers.tex(tag,name) - input.aux.load_files(tag) +function logs.extendbanner(_banner_,_verbose_) + banner = banner .. " | ".. _banner_ + if _verbose_ ~= nil then + logs.setverbose(what) + end end --- generators: +logs.verbose = false +logs.report = logs.tex.report +logs.simple = logs.tex.report -function input.loadlists() - for _, hash in ipairs(input.instance.hashes) do - input.generatedatabase(hash.tag) +function logs.reportlines(str) -- todo: + for line in str:gmatch("(.-)[\n\r]") do + logs.report(line) end end -function input.generatedatabase(specification) - return input.methodhandler('generators', specification) +function logs.reportline() -- for scripts too + logs.report() end -local weird = lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t")) +logs.simpleline = logs.reportline -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) +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 - 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: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 --- savers, todo +--~ 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 -function input.savefiles() - input.aux.save_data('files', function(k,v) - return input.instance.validfile(k,v) -- path, name - 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 --- 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. +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' } -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 +-- 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 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 +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 -end -function input.split_path(str) - if type(str) == 'table' then - return str + 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 - return file.split_path(str) + -- 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 input.join_path(str) - if type(str) == 'table' then - return file.join_path(str) - else - return str + +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 -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 +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 - ie[k] = t[1] + value = resolvers.bare_variable(e) end + ie[key] = value end + return value or "" end --- end of split/join code +function resolvers.env(key) + return instance.environment[key] or resolvers.osenv(key) +end -function input.saveoldconfig() - input.splitconfig() - input.aux.save_data('configuration', nil) - input.joinconfig() +-- + +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 -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] -]] +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 -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] .. "'," +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 - return m .. "['" .. k .. "']={'" .. concat(v,"','").. "'}," + result = resolvers.env(name) + if result then + instance.variables[name] = result + resolvers.expand_variables() + return instance.expansions[name] or "" + end 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 + 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 - 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 + return false end - t[#t+1] = "}" - return concat(t,"\n") end -if not texmf then texmf = {} end -- no longer needed, at least not here +-- {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.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 +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 - 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) + 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 -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 +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 - input.report("skipping %s for %s from %s",dataname,pathname,filename) + 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 --- some day i'll use the nested approach, but not yet (actually we even drop --- engine/progname support since we have only luatex now) +-- we follow a rather traditional approach: -- --- first texmfcnf.lua files are located, next the cached texmf.cnf files +-- (1) texmf.cnf given in TEXMFCNF +-- (2) texmf.cnf searched in default variable -- --- return { --- TEXMFBOGUS = 'effe checken of dit werkt', --- } +-- also we now follow the stupid route: if not set then just assume *one* +-- cnf file under texmf (i.e. distribution) -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 +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 - for kk, vv in pairs(v) do -- vv = variable - if type(vv) == "string" then - t[vv.."."..v] = kk - end + if trace_verbose then + logs.report("fileio","unable to check path %s",p) end + resolvers.ownpath = p end + break 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) + if not resolvers.ownpath then resolvers.ownpath = '.' end end + return resolvers.ownpath 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 +local own_places = { "SELFAUTOLOC", "SELFAUTODIR", "SELFAUTOPARENT", "TEXMFCNF" } -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 +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 -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 + 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 - input.joinconfig() + identify_own = function() end 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 +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 - if not busy then break end - end - for k,v in pairs(expansions) do - expansions[k] = v:gsub("\\", '/') + locate(resolvers.luaname,instance.luafiles) + locate(resolvers.cnfname,instance.cnffiles) 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) +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 -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 "" +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 - 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 +function resolvers.load_cnf() + local function loadoldconfigdata() + for _, fname in ipairs(instance.cnffiles) do + load_cnf_file(fname) + end 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 = { }, { } + -- 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 - 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 + else + instance.rootpath = instance.cnffiles[1] + for k,fname in ipairs(instance.cnffiles) do + instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/')) end - if #ep > 0 then - instance.extra_paths = ep -- register paths + for i=1,3 do + instance.rootpath = file.dirname(instance.rootpath) end - if #ep > n then - instance.lists = { } -- erase the cache + 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 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 +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 - 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) + for i=1,3 do + instance.rootpath = file.dirname(instance.rootpath) end - return instance.lists[str] - else - local lst = input.split_path(input.expansion(str)) - return made_list(input.aux.expanded_path(lst)) + instance.rootpath = file.collapse_path(instance.rootpath) + resolvers.loadnewconfig() + collapse_cnf_data() end + check_configuration() end +-- database loading -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])) +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 - return t end -function input.expand_path(str) - return file.join_path(input.expanded_path_list(str)) +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 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) +function resolvers.prepend_hash(type,tag,name) + if trace_locating then + logs.report("fileio","= hash prepend: %s",tag) end -end -function input.expand_path_from_var(str) - return file.join_path(input.expanded_path_list_from_var(str)) + insert(instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } ) 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' +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 -function input.variable_of_format(str) - return input.formats[str] or input.formats[input.alternatives[str]] or '' -end +-- locators -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] +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 - 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) +function resolvers.locatedatabase(specification) + return resolvers.methodhandler('locators', specification) 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 +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 - 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 +-- 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 - return newlist end -input.is_readable = { } +function resolvers.hashers.tex(tag,name) + resolvers.load_data(tag,'files') +end -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 +-- generators: + +function resolvers.loadlists() + for _, hash in ipairs(instance.hashes) do + resolvers.generatedatabase(hash.tag) end - return readable end -function input.is_readable.file(name) - return input.aux.is_readable(lfs.isfile(name), name) +function resolvers.generatedatabase(specification) + return resolvers.methodhandler('generators', specification) end -input.is_readable.tex = input.is_readable.file +-- starting with . or .. etc or funny char --- name --- name/name +local weird = lpeg.P(".")^1 + lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t")) -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 - } +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 - 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 + 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 input.trace > 1 then - input.logger('! blobpath no: %s (%s)',blobpath,bname) + elseif mode == 'directory' then + m = m + 1 + if path then + action(path..'/'..name) + else + action(name) + end end end end end - if #filelist > 0 then - return filelist - else - return nil + action() + if trace_verbose then + logs.report("fileio","%s files found on %s directories with %s uppercase remappings",n,m,r) end end -function input.suffix_of_format(str) - if input.suffixes[str] then - return input.suffixes[str][1] - else - return "" - end -end +-- savers, todo -function input.suffixes_of_format(str) - if input.suffixes[str] then - return input.suffixes[str] - else - return {} - end +function resolvers.savefiles() + resolvers.save_data('files') end -do +-- 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. - -- called about 700 times for an empty doc (font initializations etc) - -- i need to weed the font files for redundant calls +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 - 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) +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 - function input.aux.rootbased_path(filename) - return rootbased:match(filename) +end +function resolvers.split_path(str) + if type(str) == 'table' then + return str + else + return file.split_path(str) end - - function input.normalize_name(original) - return original +end +function resolvers.join_path(str) + if type(str) == 'table' then + return file.join_path(str) + else + return str 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 +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 --- split the next one up, better for jit +-- 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 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] +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 - 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 + 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 - end - if not ok and input.trace > 0 then - input.logger('? qualified: %s', filename) + t[#t+1] = "\t}," + else + t[#t+1] = dump(k,fk,"\t") 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 + 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 - filetype = instance.format - if input.trace > 0 then - input.logger('! using given filetype: %s',filetype) + 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 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," | ")) + 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 - 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 + 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 - -- 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 + 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 - -- 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 + if trace_verbose then + logs.report("fileio","skipping %s for %s from %s",dataname,pathname,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("^!+", '') - 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 + 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 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 + 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 - else - -- no access needed for non existing path, speedup (esp in large tree with lots of fake) end end end + instance['setup'][pathname] = t + else + instance['setup'][pathname] = data end - if not done and doscan then - -- todo: slow path scanning + else + if trace_verbose then + logs.report("fileio","skipping configuration file %s",filename) end - if done and not instance.allresults then break 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 - 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) +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 - return result + resolvers.joinconfig() 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 +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 - instance.fakepaths[name] = 2 -- no directory + 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 - return (instance.fakepaths[name] == 1) end -if not input.concatinators then input.concatinators = { } end +function resolvers.variable(name) + return entry(instance.variables,name) +end -input.concatinators.tex = file.join -input.concatinators.file = input.concatinators.tex +function resolvers.expansion(name) + return entry(instance.expansions,name) +end -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 +function resolvers.is_variable(name) + return is_entry(instance.variables,name) end -function input.find_file(filename,filetype,mustexist) - return (input.find_files(filename,filetype,mustexist)[1] or "") +function resolvers.is_expansion(name) + return is_entry(instance.expansions,name) 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 +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.find_given_file(filename) - return (input.find_given_files(filename)[1] or "") +function resolvers.unexpanded_path(str) + return file.join_path(resolvers.unexpanded_path_list(str)) 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 = ".*" +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 - 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 + + 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 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 + for p in gmatch(paths,"[^,]+") do + if not done[p] then + ep[#ep+1] = resolvers.clean_path(p) + done[p] = true 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 + 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 - 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("\n") - f:write("\n") - if jobname then - f:write("\t" .. jobname .. "\n") + if #ep > 0 then + instance.extra_paths = ep -- register paths end - f:write("\t\n") - for _,v in pairs(sorted(instance.foundintrees)) do -- ipairs - f:write("\t\t" .. v .. "\n") + if #ep > n then + instance.lists = { } -- erase the cache end - f:write("\t\n") - f:write("\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) +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 - if input.verbose then - report('') + -- 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 - 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 + -- 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 --- 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 +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 - 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 + return t end -function input.method_is_file(filename) - return input.splitmethod(filename).scheme == 'file' +function resolvers.expand_path(str) + return file.join_path(resolvers.expanded_path_list(str)) end -function table.sequenced(t,sep) -- temp here - local s = { } - for k, v in pairs(t) do - s[#s+1] = k .. "=" .. v +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 - 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 +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 input[what].tex(filename,filetype) -- todo: specification + return resolvers.expanded_path_list(tmp) end end --- also inside next test? +function resolvers.expand_path_from_var(str) + return file.join_path(resolvers.expanded_path_list_from_var(str)) +end -function input.findtexfile(filename, filetype) - return input.methodhandler('finders',input.normalize_name(filename), filetype) +function resolvers.format_of_var(str) + return formats[str] or formats[alternatives[str]] or '' end -function input.opentexfile(filename) - return input.methodhandler('openers',input.normalize_name(filename)) +function resolvers.format_of_suffix(str) + return suffixmap[file.extname(str)] or 'tex' 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)) +function resolvers.variable_of_format(str) + return formats[str] or formats[alternatives[str]] or '' 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) +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 input.texdatablob(filename, filetype) - local ok, data, size = input.loadbinfile(filename, filetype) - return data or "" +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 -input.loadtexfile = input.texdatablob +resolvers.isreadable = { } -function input.openfile(filename) - local fullname = input.findtexfile(filename) - if fullname and (fullname ~= "") then - return input.opentexfile(fullname) - else - return nil +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 -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 +resolvers.isreadable.tex = resolvers.isreadable.file ---- ctx - --- maybe texinputs + font paths --- maybe positive selection tex/context fonts/tfm|afm|vf|opentype|type1|map|enc - -input.validators = { } -input.validators.visibility = { } +-- name +-- name/name -function input.validators.visibility.default(path, name) - return true +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 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$") - ) +function resolvers.suffix_of_format(str) + if suffixes[str] then + return suffixes[str][1] + else + return "" + end 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 +function resolvers.suffixes_of_format(str) + if suffixes[str] then + return suffixes[str] else - return nil + return {} 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.register_in_trees(name) + if not find(name,"^%.") then + instance.foundintrees[name] = (instance.foundintrees[name] or 0) + 1 -- maybe only one end end -function input.do_with_var(name,func) - func(input.aux.expanded_var(name)) +-- 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 -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 +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 - 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) + 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 - 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") + -- 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 - local newdata = io.loaddata(newscript) - if newdata then - input.report("old script content replaced by new content") - io.savedata(oldscript,newdata) + 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 - else - input.report("unable to load new script") 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 ---~ print(table.serialize(input.aux.splitpathexpr("/usr/share/texmf-{texlive,tetex}", {}))) - --- command line resolver: +resolvers.concatinators.tex = file.join +resolvers.concatinators.file = resolvers.concatinators.tex ---~ 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 "") +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 - 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 + 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 - 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 + instance.format = '' + return result +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 +function resolvers.find_file(filename,filetype,mustexist) + return (resolvers.find_files(filename,filetype,mustexist)[1] or "") +end - local function resolve(str) - if type(str) == "table" then - for k, v in pairs(str) do - str[k] = resolve(v) or v +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 - 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 + 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 - - input.resolve = resolve - + return result 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 +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 -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-- -

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 structured file. Actually, any logging that -is hooked into callbacks will be \XML\ by default.

---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-- -

This looks pretty ugly but we need to speed things up a bit.

---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 { } +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 -logs.level = 0 +function resolvers.find_wildcard_file(filename) + return (resolvers.find_wildcard_files(filename)[1] or "") +end -local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format +-- main user functions -if texlua then - write_nl = print - write = io.write +function resolvers.automount() + -- implemented later end -function logs.xml.report(category,fmt,...) -- new - write_nl(format("%s",category,format(fmt,...))) +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 logs.xml.line(fmt,...) -- new - write_nl(format("%s",format(fmt,...))) + +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 -function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end -function logs.xml.stop () if logs.level > 0 then tw("") end end -function logs.xml.push () if logs.level > 0 then tw("" ) end end +-- strtab -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,...)) +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 -function logs.set_level(level) - logs.level = logs.levels[level] or level +-- 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 logs.set_method(method) - for _, v in pairs(logs.functions) do - logs[v] = logs[method][v] or function() 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 - if callback and input[method] then - for _, cb in pairs(logs.callbacks) do - callback.register(cb, input[method][cb]) - 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 logs.xml.start_page_number() - write_nl(format("

%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 logs.xml.stop_page_number() - write("/>") - write_nl("") +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 logs.xml.report_output_pages(p,b) - write_nl(format("", p)) - write_nl(format("", b)) - write_nl("") +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 logs.xml.report_output_log() +function resolvers.do_with_var(name,func) + func(expanded_var(name)) end -function input.logger(...) -- assumes test for input.trace > n - if input.trace > 0 then - logs.report(...) +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 input.report(fmt,...) - if input.verbose then - logs.report(input.banner or "report",format(fmt,...)) +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 input.reportlines(str) -- todo: - for line in str:gmatch("(.-)[\n\r]") do - logs.report(input.banner or "report",line) +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 -input.moreinfo = [[ -more information about ConTeXt and the tools that come with it can be found at: +texconfig.kpse_init = false -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 -]] +kpse = { original = kpse } setmetatable(kpse, { __index = function(k,v) return resolvers[v] end } ) -function input.help(banner,message) - if not input.verbose then - input.verbose = true - -- input.report(banner,"\n") - end - input.report(banner,"\n") - input.report("") - input.reportlines(message) - if input.moreinfo and input.moreinfo ~= "" then - input.report("") - input.reportlines(input.moreinfo) - end -end +-- for a while -logs.set_level('error') -logs.set_method('tex') +input = resolvers + + +end -- of closure +do -- create closure to overcome 200 locals limit -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.

--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--

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.

Examples of usage can be found in the font related code.

--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 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 + 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 - -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) +-- status info -function input.storage.register(...) - input.storage.data[#input.storage.data+1] = { ... } -end +statistics.register("used config path", function() return caches.configpath() end) +statistics.register("used cache path", function() return caches.temp() or "?" end) -function input.storage.evaluate(name) - input.storage.evaluators[#input.storage.evaluators+1] = name -end +-- experiment (code will move) -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-- -

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 structured file. Actually, any logging that -is hooked into callbacks will be \XML\ by default.

---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-- -

This looks pretty ugly but we need to speed things up a bit.

---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' -} +-- zip:///oeps.zip?name=bla/bla.tex +-- zip:///oeps.zip?tree=tex/texmf-local -logs.callbacks = { - 'start_page_number', - 'stop_page_number', - 'report_output_pages', - 'report_output_log' -} +local function validzip(str) -- todo: use url splitter + if not find(str,"^zip://") then + return "zip:///" .. str + else + return str + end +end -logs.tracers = { -} +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.xml = logs.xml or { } -logs.tex = logs.tex or { } +function zip.closearchive(name) + if not name or (name == "" and archives[name]) then + zip.close(archives[name]) + archives[name] = nil + end +end -logs.level = 0 +-- zip:///texmf.zip?tree=/tex/texmf +-- zip:///texmf.zip?tree=/tex/texmf-local +-- zip:///texmf-mine.zip?tree=/tex/texmf-projects -local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format +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 -if texlua then - write_nl = print - write = io.write +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.report(category,fmt,...) -- new - write_nl(format("%s",category,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.line(fmt,...) -- new - write_nl(format("%s",format(fmt,...))) + +function resolvers.isreadable.zip(name) + return true end -function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end -function logs.xml.stop () if logs.level > 0 then tw("") end end -function logs.xml.push () if logs.level > 0 then tw("" ) end 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 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 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.tex.line(fmt,...) -- new - write_nl(format(fmt,...)) + +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_level(level) - logs.level = logs.levels[level] or level +-- 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 logs.set_method(method) - for _, v in pairs(logs.functions) do - logs[v] = logs[method][v] or function() end +function resolvers.register_zip_file(z,tree) + local files, filter = { }, "" + if tree == "" then + filter = "^(.+)/(.-)$" + else + filter = format("^%s/(.+)/(.-)$",tree) end - if callback and input[method] then - for _, cb in pairs(logs.callbacks) do - callback.register(cb, input[method][cb]) + 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.start_page_number() - write_nl(format("

") - 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_pages(p,b) - write_nl(format("", p)) - write_nl(format("", b)) - write_nl("") +function openers.curl(protocol,filename) + return openers.generic(protocol,filename) end -function logs.xml.report_output_log() +function loaders.curl(protocol,filename) + return loaders.generic(protocol,filename) end -function input.logger(...) -- assumes test for input.trace > n - if input.trace > 0 then - logs.report(...) +-- 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-- +

This file is used when we want the input handlers to behave like +kpsewhich. What to do with the following:

+ + +{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c} +$SELFAUTOLOC : /usr/tex/bin/platform +$SELFAUTODIR : /usr/tex/bin +$SELFAUTOPARENT : /usr/tex + + +

How about just forgetting about them?

+--ldx]]-- + +local suffixes = resolvers.suffixes +local formats = resolvers.formats + +suffixes['gf'] = { 'gf' } +suffixes['pk'] = { '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-- +

If you wondered abou tsome of the previous mappings, how about +the next bunch:

+--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 -function input.report(fmt,...) - if input.verbose then - logs.report(input.banner or "report",format(fmt,...)) + +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 input.reportlines(str) -- todo: - for line in str:gmatch("(.-)[\n\r]") do - logs.report(input.banner or "report",line) +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 -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') +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 - -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 - -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 }, +logs.setprogram('MTXrun',"TDS Runner Tool 1.22",environment.arguments["verbose"] or false) - pdftrimwhite = { 'pdftrimwhite.pl', false } -} +local instance = resolvers.reset() -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' +} + +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 input.runners.prepare() +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- 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-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- 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 - 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 "#{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'] = ['.gf'] # todo - @@suffixes['pk'] = ['.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 - # /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 ; "" - 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 = "

Cached alternative: #{File.basename(filename)}" - 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 << "\n" - lines << td("#{session['id']}") - 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 << "\n" - rescue - else - n += 1 - end - end - end - if n > 0 then - str = "\n" - str << "\n" - str << th('session identifier') - str << th('status') - str << th('timeout') - str << th('time') - str << th('runtime') - str << th('total') - str << th('modification time') - str << th('domain') - str << th('project') - str << th('username') - str << th('process') - str << "\n" - str << lines - str << "
\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) - "#{str}   \n" - end - - def td(str) - "#{str || ''}   \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 << "
\n
\n"
-                        str << "name".ljust(49+u.length)
-                        str << "last modified".ljust(41+u.length)
-                        str << "size".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 << '
' - else - str << 'no info' - end - end - else - str << 'no access' - end - rescue - str << "error #{$!}
"
-            str << $@.join("\n")
-            str << "
" - 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 = "#{dname}" - elsif ! @interface.get('dir:uri').empty? then # takes precedence, in case we run under cgi control - s = "#{dname}" - else - s = "#{dname}" - 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!(//i, '') - dat = "\n" - @variables.each do |key, value| - if ['password','exa:request'].include?(key) then - # skip - elsif ! value || value.empty? then - dat << "\n" - else # todo: escape 'm - dat << "#{value}\n" - end - end - dat << "\n" - if req.empty? then - req << "\n" - req << "\n" - req << "\n" - req << "'#{action}\n" unless action.empty? - # req << "'#{command}\n" unless command.empty? - # req << "'#{url}\n" unless url.empty? - req << "\n" - req << "constructed request\n" - req << dat - req << "\n" - else - # better use rexml but slower - if req =~ /]*>.*?\s*\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!(/(]*>.*?)\s*\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}#{action}#{pos}" - str.sub(/\s*.*?<\/exa:command>\s*/moi ,'') - end - req.sub!(/(]*>.*?)\s*(.*?)\s*<\/exa:action>(.*?<\/exa:request>)/moi) do - pre, act, pos = $1, $2, $3 - action = act.sub(/\.exa$/,'') if action.empty? - str = "#{pre}#{action}#{pos}" - str.sub(/\s*.*?<\/exa:command>\s*/moi ,'') - end - unless req =~ /(.*?)<\/exa:data>/moi then - req.sub!(/(<\/exa:request>)/) do dat + $1 end - end - end - req.sub!(/.*?<\/exa:filename>/moi, '') - unless @variables.empty?('exa:filename') then - req.sub!(/(<\/exa:application>)/moi) do - "#{@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 =~ /]*>.*?\s*\s*(.*?)\s*<\/exa:command>\s*.*?<\/exa:request>/moi then - command = $1 - end - if req =~ /]*>.*?\s*\s*(.*?)\s*<\/exa:url>\s*.*?<\/exa:request>/moi then - url = $1 - end - if req =~ /]*>.*?\s*\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. - -# -# -# - -# 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}" - 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') - "#{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!(/(^.*]*>.*?)\s*\s*(.*)\s*<\/exa:client>\s*(.*?<\/exa:request>.*$)/mio) do - pre, client, post = $1, $2, $3 - client.scan(/(.*?)<\/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 = "" - else - metadata = "" - end - else - metadata = '' - end - if ! htmreply || htmreply.empty? then - # in head: - htmreply = <<-EOD - - #{metadata} - - #{title} - - -

#{title}

-

#{Time.now}

- #{text} - - - EOD - else - if showtime then - exa_template = "

#{title}

\n

#{Time.now}

\n#{text}\n" - else - exa_template = "

#{title}

#{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 = "\n\n" - str << "\n" - str << " #{@session_id}\n" unless @session_id.empty? - str << " #{status}\n" unless (status || '').empty? - str << " #{exaurl}/#{url}\n" unless (url || '').empty? - str << " #{size}\n" unless (size || '').empty? - str << " #{comment}\n" unless (comment|| '').empty? - str << "\n" - return str - end - - def append_status(str='') - if @interface.true?('trace:errors') then - if $! && $@ then - str << "


Error:
#{$!}
"
-                str << $@.join("\n")
-            end
-            str << '


' - str << status_data - str << 'Paths
' - str << '
'
-            @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 << '
' - 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 = "#{title}" - end - str << "
\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!("&","&")
-                        val.gsub!("<","<")
-                        val.gsub!(">",">")
-                        val.gsub!("\n","\n    ")
-                    end
-                    str << "#{k} => #{val}\n"
-                end
-            end
-            str << "

\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>/ 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',"
#{CGI::escapeHTML(logdata)}
") - 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 = "

unable to access cache" - else - logdata = "

#{logname}" - 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>/ 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 = "

unable to access cache" - else - str = "

#{resultname}  (#{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("\n\n") - f.puts("\n") - if block_given? then - f.puts(" ok\n") - f.puts(" #{yield}\n") - else - f.puts(" error\n") - end - f.puts(" " + str + "\n") - f.puts("\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 "\n" - f.puts "\n" - f.puts " \n" - f.puts " #{dataaction}\n" unless dataaction.empty? - f.puts " #{datafile}\n" unless datafile.empty? - f.puts " #{threshold}\n" unless threshold.empty? - f.puts " \n" - f.puts " \n" - f.puts " #{domain}\n" - f.puts " #{project}\n" - f.puts " #{username}\n" - f.puts " #{password}\n" - f.puts " \n" - if datablob.empty? then - f.puts " \n" - else - f.puts " #{datablob.chomp}\n" - end - f.puts "" - 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 =~ /(\ 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*#{resultfile}" - 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 - "#{resultfile}" - 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 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 '' + 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-- +

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 structured file. Actually, any logging that +is hooked into callbacks will be \XML\ by default.

+--ldx]]-- + +logs = logs or { } +logs.xml = logs.xml or { } +logs.tex = logs.tex or { } + +--[[ldx-- +

This looks pretty ugly but we need to speed things up a bit.

+--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("%s",category,format(fmt,...))) + else + write_nl(format("",category)) + end +end +function logs.xml.line(fmt,...) -- new + if fmt then + write_nl(format("%s",format(fmt,...))) + else + write_nl("") + 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("") end end +function logs.xml.push () if logs.level > 0 then tw("" ) end end + +function logs.xml.start_run() + write_nl("") + write_nl("") -- xmlns='www.pragma-ade.com/luatex/schemas/context-job.rng' + write_nl("") +end + +function logs.xml.stop_run() + write_nl("") +end + +function logs.xml.start_page_number() + write_nl(format("

") + write_nl("") +end + +function logs.xml.report_output_pages(p,b) + write_nl(format("", p)) + write_nl(format("", b)) + write_nl("") +end + +function logs.xml.report_output_log() +end + +function logs.xml.report_tex_stat(k,v) + texiowrite_nl("log",""..tostring(v).."") +end + +local level = 0 + +function logs.xml.show_open(name) + level = level + 1 + texiowrite_nl(format("",level,name)) +end + +function logs.xml.show_close(name) + texiowrite(" ") + level = level - 1 +end + +function logs.xml.show_load(name) + texiowrite_nl(format("",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: + 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-- +

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.

+ + +TEXMFCACHE=$TMP;$TEMP;$TMPDIR;$TEMPDIR;$HOME;$TEXMFVAR;$VARTEXMF;. + + +

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.

+--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-- +

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).

+ +

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.

+ +

Examples of usage can be found in the font related code.

+--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-- +

This file is used when we want the input handlers to behave like +kpsewhich. What to do with the following:

+ + +{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c} +$SELFAUTOLOC : /usr/tex/bin/platform +$SELFAUTODIR : /usr/tex/bin +$SELFAUTOPARENT : /usr/tex + + +

How about just forgetting about them?

+--ldx]]-- + +local suffixes = resolvers.suffixes +local formats = resolvers.formats + +suffixes['gf'] = { 'gf' } +suffixes['pk'] = { '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-- +

If you wondered abou tsome of the previous mappings, how about +the next bunch:

+--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 .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-- +

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 based one. +The find based parser can be found in l-xml-edu.lua along with other older code.

+ +

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 we also need +this module for process management, like handling and +files.

+ + +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) + + +

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.

+--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-- +

This module can be used stand alone but also inside in +which case it hooks into the tracker code. Therefore we provide a few +functions that set the tracers.

+--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-- +

First a hack to enable namespace resolving. A namespace is characterized by +a . The following function associates a namespace prefix with a +pattern. We use , 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.

+--ldx]]-- + +xml.xmlns = xml.xmlns or { } + +local check = lpeg.P(false) +local parse = check + +--[[ldx-- +

The next function associates a namespace prefix with an . This +normally happens independent of parsing.

+ + +xml.registerns("mml","mathml") + +--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-- +

The next function also registers a namespace, but this time we map a +given namespace prefix onto a registered one, using the given +. This used for attributes like xmlns:m.

+ + +xml.checkns("m","http://www.w3.org/mathml") + +--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-- +

Next we provide a way to turn an into a registered +namespace. This used for the xmlns attribute.

+ + +resolvedns = xml.resolvens("http://www.w3.org/mathml") + + +This returns mml. +--ldx]]-- + +function xml.resolvens(url) + return parse:match(lower(url)) or "" +end + +--[[ldx-- +

A namespace in an element can be remapped onto the registered +one efficiently by using the xml.xmlns table.

+--ldx]]-- + +--[[ldx-- +

This version uses . 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 files that +took 12.5 seconds to load (1.5 for file io and the rest for tree building). With +the implementation we got that down to less 7.3 seconds. Loading the 14 + interface definition files (2.6 meg) went down from 1.05 seconds to 0.55.

+ +

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 + code to it.

+ + + + + + + + + + +

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:

+ + +local x = xml.convert(somestring) + + +

An optional second boolean argument tells this function not to create a root +element.

+--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("Packaging data in an xml like table is done with the following +function. Maybe it will go away (when not used).

+--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-- +

We cannot load an from a filehandle so we need to load +the whole file first. The function accepts a string representing +a filename or a file handle.

+--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-- +

When we inject new elements, we need to convert strings to +valid trees, which is what the next function does.

+--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-- +

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!

+--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-- +

In 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.

+--ldx]]-- + +-- todo: add 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("",edt[1])) + handle("") + elseif etg == "@cm@" then + -- handle(format("",edt[1])) + handle("") + elseif etg == "@cd@" then + -- handle(format("",edt[1])) + handle("") + elseif etg == "@dt@" then + -- handle(format("",edt[1])) + handle("") + 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("",ens,etg)) + handle("") + 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("",etg)) + handle("") + 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-- +

At the cost of some 25% runtime overhead you can first convert the tree to a string +and then handle the lot.

+--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-- +

The next function operated on the content only and needs a handle function +that accepts a string.

+--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-- +

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):

+ + +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 + + +

The save function is given below.

+--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-- +

A few helpers:

+--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-- +

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:

+ + +dt[k] = xml.empty() or xml.empty(dt,k) + +--ldx]]-- + +function xml.empty(dt,k) + if dt and k then + dt[k] = "" + return dt[k] + else + return "" + end +end + +--[[ldx-- +

The next helper assigns a tree (or string). Usage:

+ + +dt[k] = xml.assign(root) or xml.assign(dt,k,root) + +--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-- +

This module can be used stand alone but also inside 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.

+--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-- +

We've now arrived at an intersting part: accessing the tree using a subset +of and since we're not compatible we call it . We +will explain more about its usage in other documents.

+--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("\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-- +

An 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:

+ + +r : the root element of the data table +d : the data table of the result +t : the index in the data table of the result + + +

Access to the root and data table makes it possible to construct insert and delete +functions.

+--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-- +

Next come all kind of locators and manipulators. The most generic function here +is xml.filter(root,pattern). All registers functions in the filters namespace +can be path of a search path, as in:

+ + +local r, d, k = xml.filter(root,"/a/b/c/position(4)" + +--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-- +

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.

+--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-- +

The following functions collect elements and texts.

+--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-- +

Often using an iterators looks nicer in the code than passing handler +functions. The book describes how to use coroutines for that +purpose (). This permits +code like:

+ + +for r, d, k in xml.elements(xml.load('text.xml'),"title") do + print(d[k]) +end + + +

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:

+ + +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 + + +

We use the function variants in the filters.

+--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-- +

We've now arrives at the functions that manipulate the tree.

+--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-- +

Here are a few synonyms.

+--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-- +

The following helper functions best belong to the lmxl-ini +module. Some are here because we need then in the mk +document and other manuals, others came up when playing with +this module. Since this module is also used in we've +put them here instead of loading mode modules there then needed.

+--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 = { ['&'] = '&', ['<'] = '<', ['>'] = '>', ['"'] = '"' } +--~ 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("<")/"<" + S(">")/">" + S("&")/"&" + 1)^0) +local normal = (1 - S("<&>"))^0 +local special = P("<")/"<" + P(">")/">" + P("&")/"&" +local escaped = Cs(normal * (special * normal)^0) + +-- 100 * 1000 * "oeps< oeps> oeps&" : gsub:lpeg == 0153:0280:0151:0080 (last one by roberto) + +-- unescaped = Cs((S("<")/"<" + S(">")/">" + S("&")/"&" + 1)^0) +-- unescaped = Cs((((P("&")/"") * (P("lt")/"<" + P("gt")/">" + P("amp")/"&") * (P(";")/"")) + 1)^0) +local normal = (1 - S"&")^0 +local special = P("<")/"<" + P(">")/">" + P("&")/"&" +local unescaped = Cs(normal * (special * normal)^0) + +-- 100 * 5000 * "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([[ +--~ +--~ 01 +--~ 02 +--~ 03 +--~ OK +--~ 05 +--~ 06 +--~ ALSO OK +--~ +--~ ]]) + +--~ 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 = [[ +--~ +--~ +--~ my secret +--~ +--~ ]] + +--~ x = xml.convert([[ +--~ 0102xx03OK +--~ ]]) +--~ 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-- +

We provide (at least here) two entity handlers. The more extensive +resolver consults a hash first, tries to convert to next, +and finaly calls a handler when defines. When this all fails, the +original entity is returned.

+--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-- +

The following helper functions best belong to the lmxl-ini +module. Some are here because we need then in the mk +document and other manuals, others came up when playing with +this module. Since this module is also used in we've +put them here instead of loading mode modules there then needed.

+--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 = { ['&'] = '&', ['<'] = '<', ['>'] = '>', ['"'] = '"' } +--~ 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("<")/"<" + S(">")/">" + S("&")/"&" + 1)^0) +local normal = (1 - S("<&>"))^0 +local special = P("<")/"<" + P(">")/">" + P("&")/"&" +local escaped = Cs(normal * (special * normal)^0) + +-- 100 * 1000 * "oeps< oeps> oeps&" : gsub:lpeg == 0153:0280:0151:0080 (last one by roberto) + +-- unescaped = Cs((S("<")/"<" + S(">")/">" + S("&")/"&" + 1)^0) +-- unescaped = Cs((((P("&")/"") * (P("lt")/"<" + P("gt")/">" + P("amp")/"&") * (P(";")/"")) + 1)^0) +local normal = (1 - S"&")^0 +local special = P("<")/"<" + P(">")/">" + P("&")/"&" +local unescaped = Cs(normal * (special * normal)^0) + +-- 100 * 5000 * "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 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 '' + 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-- +

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 structured file. Actually, any logging that +is hooked into callbacks will be \XML\ by default.

+--ldx]]-- + +logs = logs or { } +logs.xml = logs.xml or { } +logs.tex = logs.tex or { } + +--[[ldx-- +

This looks pretty ugly but we need to speed things up a bit.

+--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("%s",category,format(fmt,...))) + else + write_nl(format("",category)) + end +end +function logs.xml.line(fmt,...) -- new + if fmt then + write_nl(format("%s",format(fmt,...))) + else + write_nl("") + 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("") end end +function logs.xml.push () if logs.level > 0 then tw("" ) end end + +function logs.xml.start_run() + write_nl("") + write_nl("") -- xmlns='www.pragma-ade.com/luatex/schemas/context-job.rng' + write_nl("") +end + +function logs.xml.stop_run() + write_nl("") +end + +function logs.xml.start_page_number() + write_nl(format("

") + write_nl("") +end + +function logs.xml.report_output_pages(p,b) + write_nl(format("", p)) + write_nl(format("", b)) + write_nl("") +end + +function logs.xml.report_output_log() +end + +function logs.xml.report_tex_stat(k,v) + texiowrite_nl("log",""..tostring(v).."") +end + +local level = 0 + +function logs.xml.show_open(name) + level = level + 1 + texiowrite_nl(format("",level,name)) +end + +function logs.xml.show_close(name) + texiowrite(" ") + level = level - 1 +end + +function logs.xml.show_load(name) + texiowrite_nl(format("",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: + 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-- +

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.

+ + +TEXMFCACHE=$TMP;$TEMP;$TMPDIR;$TEMPDIR;$HOME;$TEXMFVAR;$VARTEXMF;. + + +

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.

+--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-- +

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).

+ +

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.

+ +

Examples of usage can be found in the font related code.

+--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-- +

This file is used when we want the input handlers to behave like +kpsewhich. What to do with the following:

+ + +{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c} +$SELFAUTOLOC : /usr/tex/bin/platform +$SELFAUTODIR : /usr/tex/bin +$SELFAUTOPARENT : /usr/tex + + +

How about just forgetting about them?

+--ldx]]-- + +local suffixes = resolvers.suffixes +local formats = resolvers.formats + +suffixes['gf'] = { 'gf' } +suffixes['pk'] = { '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-- +

If you wondered abou tsome of the previous mappings, how about +the next bunch:

+--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- + fullname = "mtx-" .. filename + fullname = found(fullname) or resolvers.find_file(fullname) + if fullname and fullname ~= "" then + return fullname + end + -- context namespace, mtx-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- + 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 + 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 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 '' + 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-- +

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 structured file. Actually, any logging that +is hooked into callbacks will be \XML\ by default.

+--ldx]]-- + +logs = logs or { } +logs.xml = logs.xml or { } +logs.tex = logs.tex or { } + +--[[ldx-- +

This looks pretty ugly but we need to speed things up a bit.

+--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("%s",category,format(fmt,...))) + else + write_nl(format("",category)) + end +end +function logs.xml.line(fmt,...) -- new + if fmt then + write_nl(format("%s",format(fmt,...))) + else + write_nl("") + 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("") end end +function logs.xml.push () if logs.level > 0 then tw("" ) end end + +function logs.xml.start_run() + write_nl("") + write_nl("") -- xmlns='www.pragma-ade.com/luatex/schemas/context-job.rng' + write_nl("") +end + +function logs.xml.stop_run() + write_nl("") +end + +function logs.xml.start_page_number() + write_nl(format("

") + write_nl("") +end + +function logs.xml.report_output_pages(p,b) + write_nl(format("", p)) + write_nl(format("", b)) + write_nl("") +end + +function logs.xml.report_output_log() +end + +function logs.xml.report_tex_stat(k,v) + texiowrite_nl("log",""..tostring(v).."") +end + +local level = 0 + +function logs.xml.show_open(name) + level = level + 1 + texiowrite_nl(format("",level,name)) +end + +function logs.xml.show_close(name) + texiowrite(" ") + level = level - 1 +end + +function logs.xml.show_load(name) + texiowrite_nl(format("",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: + 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-- +

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.

+ + +TEXMFCACHE=$TMP;$TEMP;$TMPDIR;$TEMPDIR;$HOME;$TEXMFVAR;$VARTEXMF;. + + +

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.

+--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-- +

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).

+ +

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.

+ +

Examples of usage can be found in the font related code.

+--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-- +

This file is used when we want the input handlers to behave like +kpsewhich. What to do with the following:

+ + +{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c} +$SELFAUTOLOC : /usr/tex/bin/platform +$SELFAUTODIR : /usr/tex/bin +$SELFAUTOPARENT : /usr/tex + + +

How about just forgetting about them?

+--ldx]]-- + +local suffixes = resolvers.suffixes +local formats = resolvers.formats + +suffixes['gf'] = { 'gf' } +suffixes['pk'] = { '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-- +

If you wondered abou tsome of the previous mappings, how about +the next bunch:

+--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 .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-- +

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 based one. +The find based parser can be found in l-xml-edu.lua along with other older code.

+ +

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 we also need +this module for process management, like handling and +files.

+ + +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) + + +

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.

+--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-- +

This module can be used stand alone but also inside in +which case it hooks into the tracker code. Therefore we provide a few +functions that set the tracers.

+--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-- +

First a hack to enable namespace resolving. A namespace is characterized by +a . The following function associates a namespace prefix with a +pattern. We use , 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.

+--ldx]]-- + +xml.xmlns = xml.xmlns or { } + +local check = lpeg.P(false) +local parse = check + +--[[ldx-- +

The next function associates a namespace prefix with an . This +normally happens independent of parsing.

+ + +xml.registerns("mml","mathml") + +--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-- +

The next function also registers a namespace, but this time we map a +given namespace prefix onto a registered one, using the given +. This used for attributes like xmlns:m.

+ + +xml.checkns("m","http://www.w3.org/mathml") + +--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-- +

Next we provide a way to turn an into a registered +namespace. This used for the xmlns attribute.

+ + +resolvedns = xml.resolvens("http://www.w3.org/mathml") + + +This returns mml. +--ldx]]-- + +function xml.resolvens(url) + return parse:match(lower(url)) or "" +end + +--[[ldx-- +

A namespace in an element can be remapped onto the registered +one efficiently by using the xml.xmlns table.

+--ldx]]-- + +--[[ldx-- +

This version uses . 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 files that +took 12.5 seconds to load (1.5 for file io and the rest for tree building). With +the implementation we got that down to less 7.3 seconds. Loading the 14 + interface definition files (2.6 meg) went down from 1.05 seconds to 0.55.

+ +

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 + code to it.

+ + + + + + + + + + +

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:

+ + +local x = xml.convert(somestring) + + +

An optional second boolean argument tells this function not to create a root +element.

+--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("Packaging data in an xml like table is done with the following +function. Maybe it will go away (when not used).

+--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-- +

We cannot load an from a filehandle so we need to load +the whole file first. The function accepts a string representing +a filename or a file handle.

+--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-- +

When we inject new elements, we need to convert strings to +valid trees, which is what the next function does.

+--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-- +

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!

+--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-- +

In 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.

+--ldx]]-- + +-- todo: add 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("",edt[1])) + handle("") + elseif etg == "@cm@" then + -- handle(format("",edt[1])) + handle("") + elseif etg == "@cd@" then + -- handle(format("",edt[1])) + handle("") + elseif etg == "@dt@" then + -- handle(format("",edt[1])) + handle("") + 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("",ens,etg)) + handle("") + 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("",etg)) + handle("") + 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-- +

At the cost of some 25% runtime overhead you can first convert the tree to a string +and then handle the lot.

+--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-- +

The next function operated on the content only and needs a handle function +that accepts a string.

+--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-- +

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):

+ + +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 + + +

The save function is given below.

+--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-- +

A few helpers:

+--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-- +

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:

+ + +dt[k] = xml.empty() or xml.empty(dt,k) + +--ldx]]-- + +function xml.empty(dt,k) + if dt and k then + dt[k] = "" + return dt[k] + else + return "" + end +end + +--[[ldx-- +

The next helper assigns a tree (or string). Usage:

+ + +dt[k] = xml.assign(root) or xml.assign(dt,k,root) + +--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-- +

This module can be used stand alone but also inside 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.

+--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-- +

We've now arrived at an intersting part: accessing the tree using a subset +of and since we're not compatible we call it . We +will explain more about its usage in other documents.

+--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("\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-- +

An 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:

+ + +r : the root element of the data table +d : the data table of the result +t : the index in the data table of the result + + +

Access to the root and data table makes it possible to construct insert and delete +functions.

+--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-- +

Next come all kind of locators and manipulators. The most generic function here +is xml.filter(root,pattern). All registers functions in the filters namespace +can be path of a search path, as in:

+ + +local r, d, k = xml.filter(root,"/a/b/c/position(4)" + +--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-- +

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.

+--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-- +

The following functions collect elements and texts.

+--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-- +

Often using an iterators looks nicer in the code than passing handler +functions. The book describes how to use coroutines for that +purpose (). This permits +code like:

+ + +for r, d, k in xml.elements(xml.load('text.xml'),"title") do + print(d[k]) +end + + +

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:

+ + +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 + + +

We use the function variants in the filters.

+--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-- +

We've now arrives at the functions that manipulate the tree.

+--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-- +

Here are a few synonyms.

+--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-- +

The following helper functions best belong to the lmxl-ini +module. Some are here because we need then in the mk +document and other manuals, others came up when playing with +this module. Since this module is also used in we've +put them here instead of loading mode modules there then needed.

+--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 = { ['&'] = '&', ['<'] = '<', ['>'] = '>', ['"'] = '"' } +--~ 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("<")/"<" + S(">")/">" + S("&")/"&" + 1)^0) +local normal = (1 - S("<&>"))^0 +local special = P("<")/"<" + P(">")/">" + P("&")/"&" +local escaped = Cs(normal * (special * normal)^0) + +-- 100 * 1000 * "oeps< oeps> oeps&" : gsub:lpeg == 0153:0280:0151:0080 (last one by roberto) + +-- unescaped = Cs((S("<")/"<" + S(">")/">" + S("&")/"&" + 1)^0) +-- unescaped = Cs((((P("&")/"") * (P("lt")/"<" + P("gt")/">" + P("amp")/"&") * (P(";")/"")) + 1)^0) +local normal = (1 - S"&")^0 +local special = P("<")/"<" + P(">")/">" + P("&")/"&" +local unescaped = Cs(normal * (special * normal)^0) + +-- 100 * 5000 * "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([[ +--~ +--~ 01 +--~ 02 +--~ 03 +--~ OK +--~ 05 +--~ 06 +--~ ALSO OK +--~ +--~ ]]) + +--~ 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 = [[ +--~ +--~ +--~ my secret +--~ +--~ ]] + +--~ x = xml.convert([[ +--~ 0102xx03OK +--~ ]]) +--~ 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-- +

We provide (at least here) two entity handlers. The more extensive +resolver consults a hash first, tries to convert to next, +and finaly calls a handler when defines. When this all fails, the +original entity is returned.

+--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-- +

The following helper functions best belong to the lmxl-ini +module. Some are here because we need then in the mk +document and other manuals, others came up when playing with +this module. Since this module is also used in we've +put them here instead of loading mode modules there then needed.

+--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 = { ['&'] = '&', ['<'] = '<', ['>'] = '>', ['"'] = '"' } +--~ 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("<")/"<" + S(">")/">" + S("&")/"&" + 1)^0) +local normal = (1 - S("<&>"))^0 +local special = P("<")/"<" + P(">")/">" + P("&")/"&" +local escaped = Cs(normal * (special * normal)^0) + +-- 100 * 1000 * "oeps< oeps> oeps&" : gsub:lpeg == 0153:0280:0151:0080 (last one by roberto) + +-- unescaped = Cs((S("<")/"<" + S(">")/">" + S("&")/"&" + 1)^0) +-- unescaped = Cs((((P("&")/"") * (P("lt")/"<" + P("gt")/">" + P("amp")/"&") * (P(";")/"")) + 1)^0) +local normal = (1 - S"&")^0 +local special = P("<")/"<" + P(">")/">" + P("&")/"&" +local unescaped = Cs(normal * (special * normal)^0) + +-- 100 * 5000 * "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 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 '' + 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-- +

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 structured file. Actually, any logging that +is hooked into callbacks will be \XML\ by default.

+--ldx]]-- + +logs = logs or { } +logs.xml = logs.xml or { } +logs.tex = logs.tex or { } + +--[[ldx-- +

This looks pretty ugly but we need to speed things up a bit.

+--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("%s",category,format(fmt,...))) + else + write_nl(format("",category)) + end +end +function logs.xml.line(fmt,...) -- new + if fmt then + write_nl(format("%s",format(fmt,...))) + else + write_nl("") + 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("") end end +function logs.xml.push () if logs.level > 0 then tw("" ) end end + +function logs.xml.start_run() + write_nl("") + write_nl("") -- xmlns='www.pragma-ade.com/luatex/schemas/context-job.rng' + write_nl("") +end + +function logs.xml.stop_run() + write_nl("") +end + +function logs.xml.start_page_number() + write_nl(format("

") + write_nl("") +end + +function logs.xml.report_output_pages(p,b) + write_nl(format("", p)) + write_nl(format("", b)) + write_nl("") +end + +function logs.xml.report_output_log() +end + +function logs.xml.report_tex_stat(k,v) + texiowrite_nl("log",""..tostring(v).."") +end + +local level = 0 + +function logs.xml.show_open(name) + level = level + 1 + texiowrite_nl(format("",level,name)) +end + +function logs.xml.show_close(name) + texiowrite(" ") + level = level - 1 +end + +function logs.xml.show_load(name) + texiowrite_nl(format("",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: + 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-- +

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.

+ + +TEXMFCACHE=$TMP;$TEMP;$TMPDIR;$TEMPDIR;$HOME;$TEXMFVAR;$VARTEXMF;. + + +

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.

+--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-- +

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).

+ +

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.

+ +

Examples of usage can be found in the font related code.

+--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-- +

This file is used when we want the input handlers to behave like +kpsewhich. What to do with the following:

+ + +{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c} +$SELFAUTOLOC : /usr/tex/bin/platform +$SELFAUTODIR : /usr/tex/bin +$SELFAUTOPARENT : /usr/tex + + +

How about just forgetting about them?

+--ldx]]-- + +local suffixes = resolvers.suffixes +local formats = resolvers.formats + +suffixes['gf'] = { 'gf' } +suffixes['pk'] = { '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-- +

If you wondered abou tsome of the previous mappings, how about +the next bunch:

+--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- + fullname = "mtx-" .. filename + fullname = found(fullname) or resolvers.find_file(fullname) + if fullname and fullname ~= "" then + return fullname + end + -- context namespace, mtx-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- + 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 + 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-- +

This module implements a couple of cleanup methods. We need these +in order to meet the specification. Watch the double +parenthesis; they are needed because otherwise we would pass more +than one argument to .

+--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 {<>}% + \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 <>% + \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 -> <> >> +% object_2 -> <> >> +% rendering -> <> + +\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 + {<>} + +\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 {<>}% + \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 <>}} + +%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{<>}% + \appendtoPDFdocumentextgstates{/GSnegative \PDFobjref\pdflastobj}% + \immediate\pdfobj{<>}% + \appendtoPDFdocumentextgstates{/GSpositive \PDFobjref\pdflastobj}% + \global\let\initializePDFnegative\relax} + +\def\initializePDFoverprint + {\immediate\pdfobj{<>}% /op defaults to /OP + \appendtoPDFdocumentextgstates{/GSknockout \PDFobjref\pdflastobj}% + \immediate\pdfobj{<>}% /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 <>}} + +\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-- +

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.

+--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("\n"), + 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("") + result[#result+1] = format("") + for id, categories in next, session.data do + result[#result+1] = format(" ",id) + for name, entry in next, categories do + if not entries or entries[name] then + result[#result+1] = format(" ",name) + for key, value in next, entry do + value = escaped_pattern:match(value) + if value ~= "" then + result[#result+1] = format(" %s",key,value) + end + end + result[#result+1] = format(" ") + end + end + result[#result+1] = format(" ") + end + result[#result+1] = format("") + 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/catc-sym.tex b/tex/context/base/catc-sym.tex new file mode 100644 index 000000000..49d94815c --- /dev/null +++ b/tex/context/base/catc-sym.tex @@ -0,0 +1,118 @@ +%D \module +%D [ file=catc-sym, +%D version=1997.01.03, % moved code +%D title=\CONTEXT\ Catcode Macros, +%D subtitle=Some Handy Constants, +%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 We want to have access to the raw alternatives of the +%D special characters. We use a \type {\xdef} instead of +%D \type {\let} because we need an expandable token in a +%D \type {\write}. + +\bgroup + +\catcode`B=\@@begingroup +\catcode`E=\@@endgroup +\catcode`.=\@@escape + +.catcode `.{ 12 .xdef .letteropenbrace B.string{E +.catcode `.} 12 .xdef .letterclosebrace B.string}E +.catcode `.& 12 .xdef .letterampersand B.string&E +.catcode `.< 12 .xdef .letterless B.string 12 .xdef .lettermore B.string>E +.catcode `.# 12 .xdef .letterhash B.string#E +.catcode `." 12 .xdef .letterdoublequote B.string"E +.catcode `.' 12 .xdef .lettersinglequote B.string'E +.catcode `.$ 12 .xdef .letterdollar B.string$E +.catcode `.% 12 .xdef .letterpercent B.string%E +.catcode `.^ 12 .xdef .letterhat B.string^E +.catcode `._ 12 .xdef .letterunderscore B.string_E +.catcode `.| 12 .xdef .letterbar B.string|E +.catcode `.~ 12 .xdef .lettertilde B.string~E +.catcode `.\ 12 .xdef .letterbackslash B.string\E +.catcode `./ 12 .xdef .letterslash B.string/E +.catcode `.? 12 .xdef .letterquestionmark B.string?E +.catcode `.! 12 .xdef .letterexclamationmark B.string!E +.catcode `.@ 12 .xdef .letterat B.string@E +.catcode `.: 12 .xdef .lettercolon B.string:E + + .global .let .letterescape .letterbackslash + .global .let .letterbgroup .letteropenbrace + .global .let .letteregroup .letterclosebrace + .global .let .letterleftbrace .letteropenbrace + .global .let .letterrightbrace .letterclosebrace + +.egroup + +%D \macros +%D {uncatcodespecials,setnaturalcatcodes,setnormalcatcodes, +%D uncatcodecharacters,uncatcodeallcharacters, +%D uncatcodespacetokens} +%D +%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} +\def\setnormalcatcodes {\setcatcodetable\ctxcatcodes} % maybe \texcatcodes +\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. This macro is meant for \POSTSCRIPT\ and \PDF\ +%D code passed on to the backend. + +\newtoks\everyverbosechacters + +\def\setverbosecscharacter#1% + {\edef#1{\string#1}} + +\def\setverbosecscharacters + {\the\everyverbosechacters} + +\bgroup + + % 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\/} + +\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="", + description="", direction="l", linebreak="id", unicodeslot=0x3400, - }, - [0x4DB5]={ - category="lo", - cjkwd="w", - description="", - direction="l", - linebreak="id", - unicodeslot=0x4DB5, + range= 0x4DB5, }, [0x4DC0]={ category="so", @@ -83508,17 +84216,11 @@ characters.data={ [0x4E00]={ category="lo", cjkwd="w", - description="", + description="", direction="l", linebreak="id", unicodeslot=0x4E00, - }, - [0x9FBB]={ - category="lo", - cjkwd="w", - description="", - linebreak="id", - unicodeslot=0x9FBB, + range=0x9FBB, }, [0xA000]={ category="lo", @@ -94186,18 +94888,11 @@ characters.data={ [0xAC00]={ category="lo", cjkwd="w", - description="", + description="", direction="l", linebreak="h2", unicodeslot=0xAC00, - }, - [0xD7A3]={ - category="lo", - cjkwd="w", - description="", - 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="", + description="", direction="l", linebreak="id", unicodeslot=0x20000, - }, - [0x2A6D6]={ - category="lo", - cjkwd="w", - description="", - direction="l", - linebreak="id", - unicodeslot=0x2A6D6, + range=0x2A6D6, }, [0x2F800]={ category="lo", diff --git a/tex/context/base/char-enc.lua b/tex/context/base/char-enc.lua new file mode 100644 index 000000000..a4e5ac77d --- /dev/null +++ b/tex/context/base/char-enc.lua @@ -0,0 +1,163 @@ +if not modules then modules = { } end modules ['char-syn'] = { + version = 1.001, + comment = "companion to char-ini.tex", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- thanks to tex4ht for these mappings + +characters = characters or { } + +characters.synonyms = { + angle = 0x2220, + anticlockwise = 0x21BA, + arrowaxisleft = 0x2190, + arrowaxisright = 0x2192, + arrowparrleftright = 0x21C6, + arrowparrrightleft = 0x21C4, + arrowtailleft = 0x21A2, + arrowtailright = 0x21A3, + arrowtripleleft = 0x21DA, + arrowtripleright = 0x21DB, + axisshort = 0x2212, + because = 0x2235, + between = 0x226C, + check = 0x2713, + circleasteris = 0x229B, + circleequal = 0x2257, + circleminus = 0x229D, + circleR = 0x24C7, + circlering = 0x229A, + circleS = 0x24C8, + clockwise = 0x21BB, + complement = 0x2201, + curlyleft = 0x21AB, + curlyright = 0x21AC, + dblarrowdwn = 0x21CA, + dblarrowheadleft = 0x219E, + dblarrowheadright = 0x21A0, + dblarrowleft = 0x21C7, + dblarrowright = 0x21C9, + dblarrowup = 0x21C8, + defines = 0x225C, + diamond = 0x2662, + diamondsolid = 0x2666, + difference = 0x224F, + dotplus = 0x2214, + downfall = 0x22CE, + equaldotleftright = 0x2252, + equaldotrightleft = 0x2253, + equalorfollows = 0x22DF, + equalorgreater = 0x22DD, + equalorless = 0x22DC, + equalorprecedes = 0x22DE, + equalsdots = 0x2251, + followsorcurly = 0x227D, + followsorequal = 0x227F, + forces = 0x22A9, + forcesbar = 0x22AA, + fork = 0x22D4, + frown = 0x2322, + geomequivalent = 0x224E, + greaterdbleqlless = 0x22Da, + greaterdblequal = 0x2267, + greaterlessequal = 0x22DA, + greaterorapproxeql = 0x227F, + greaterorequalslant= 0x2265, + greaterorless = 0x2277, + greaterorsimilar = 0x2273, + harpoondownleft = 0x21C3, + harpoondownright = 0x21C2, + harpoonleftright = 0x21CC, + harpoonrightleft = 0x21CB, + harpoonupleft = 0x21BF, + harpoonupright = 0x21BE, + intercal = 0x22BA, + intersectiondbl = 0x22D2, + lessdbleqlgreater = 0x22DB, + lessdblequal = 0x2266, + lessequalgreater = 0x22DB, + lessorapproxeql = 0x227E, + lessorequalslant = 0x2264, + lessorgreater = 0x2276, + lessorsimilar = 0x2272, + maltesecross = 0xFFFD, + measuredangle = 0x2221, + muchgreater = 0x22D9, + muchless = 0x22D8, + multimap = 0x22B8, + multiopenleft = 0x22CB, + multiopenright = 0x22CC, + nand = 0x22BC, + orunderscore = 0x22BB, + perpcorrespond = 0x2259, + precedesorcurly = 0x227C, + precedesorequal = 0x227E, + primereverse = 0x2035, + proportional = 0x221D, + revasymptequal = 0x2243, + revsimilar = 0x223D, + rightanglene = 0x231D, + rightanglenw = 0x231C, + rightanglese = 0x231F, + rightanglesw = 0x231E, + ringinequal = 0x2256, + satisfies = 0x22A8, + shiftleft = 0x21B0, + shiftright = 0x21B1, + smile = 0x2323, + sphericalangle = 0x2222, + square = 0x25A1, + squaredot = 0x22A1, + squareimage = 0x228F, + squareminus = 0x229F, + squaremultiply = 0x22A0, + squareoriginal = 0x2290, + squareplus = 0x229E, + squaresmallsolid = 0x25AA, + squaresolid = 0x25A0, + squiggleleftright = 0x21AD, + squiggleright = 0x21DD, + star = 0x22C6, + subsetdbl = 0x22D0, + subsetdblequal = 0x2286, + supersetdbl = 0x22D1, + supersetdblequa = 0x2287, + therefore = 0x2234, + triangle = 0x25B5, + triangledownsld = 0x25BE, + triangleinv = 0x25BF, + triangleleft = 0x25C3, + triangleleftequal = 0x22B4, + triangleleftsld = 0x25C2, + triangleright = 0x25B9, + trianglerightequal = 0x22B5, + trianglerightsld = 0x25B8, + trianglesolid = 0x25B4, + uniondbl = 0x22D3, + 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--

This module implements some methods and creates additional datastructured from the big character table that we use for all kind of purposes: char-def.lua.

+ +

We assume that at this point characters.data is already +loaded!

--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--

At this point we assume that the big data table is loaded. From this table we derive a few more.

--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--

The context namespace is used to store methods and data which is rather specific to .

--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--

Instead of using a file to define the named glyphs, we use the table. After all, we have this information available anyway.

--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

Setting the lccodes is also done in a loop over the data table.

--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 @@ -479,22 +511,13 @@ end characters.valid = characters.is_valid ---[[ldx-- -

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.

---ldx]]-- - -function characters.define(c) - characters.data[characters.number(c.unicodeslot)] = c -end - --[[ldx--

--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).

--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.

--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--

Requesting lower and uppercase codes:

--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-- -

The following code is kind of messy. It is used to generate the right -unicode reference tables.

---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-syn.lua b/tex/context/base/char-syn.lua deleted file mode 100644 index a779e1a58..000000000 --- a/tex/context/base/char-syn.lua +++ /dev/null @@ -1,140 +0,0 @@ -if not modules then modules = { } end modules ['char-syn'] = { - version = 1.001, - comment = "companion to char-ini.tex", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- thanks to tex4ht for these mappings - -characters.synonyms = { - angle = 0x2220, - anticlockwise = 0x21BA, - arrowaxisleft = 0x2190, - arrowaxisright = 0x2192, - arrowparrleftright = 0x21C6, - arrowparrrightleft = 0x21C4, - arrowtailleft = 0x21A2, - arrowtailright = 0x21A3, - arrowtripleleft = 0x21DA, - arrowtripleright = 0x21DB, - axisshort = 0x2212, - because = 0x2235, - between = 0x226C, - check = 0x2713, - circleasteris = 0x229B, - circleequal = 0x2257, - circleminus = 0x229D, - circleR = 0x24C7, - circlering = 0x229A, - circleS = 0x24C8, - clockwise = 0x21BB, - complement = 0x2201, - curlyleft = 0x21AB, - curlyright = 0x21AC, - dblarrowdwn = 0x21CA, - dblarrowheadleft = 0x219E, - dblarrowheadright = 0x21A0, - dblarrowleft = 0x21C7, - dblarrowright = 0x21C9, - dblarrowup = 0x21C8, - defines = 0x225C, - diamond = 0x2662, - diamondsolid = 0x2666, - difference = 0x224F, - dotplus = 0x2214, - downfall = 0x22CE, - equaldotleftright = 0x2252, - equaldotrightleft = 0x2253, - equalorfollows = 0x22DF, - equalorgreater = 0x22DD, - equalorless = 0x22DC, - equalorprecedes = 0x22DE, - equalsdots = 0x2251, - followsorcurly = 0x227D, - followsorequal = 0x227F, - forces = 0x22A9, - forcesbar = 0x22AA, - fork = 0x22D4, - frown = 0x2322, - geomequivalent = 0x224E, - greaterdbleqlless = 0x22Da, - greaterdblequal = 0x2267, - greaterlessequal = 0x22DA, - greaterorapproxeql = 0x227F, - greaterorequalslant= 0x2265, - greaterorless = 0x2277, - greaterorsimilar = 0x2273, - harpoondownleft = 0x21C3, - harpoondownright = 0x21C2, - harpoonleftright = 0x21CC, - harpoonrightleft = 0x21CB, - harpoonupleft = 0x21BF, - harpoonupright = 0x21BE, - intercal = 0x22BA, - intersectiondbl = 0x22D2, - lessdbleqlgreater = 0x22DB, - lessdblequal = 0x2266, - lessequalgreater = 0x22DB, - lessorapproxeql = 0x227E, - lessorequalslant = 0x2264, - lessorgreater = 0x2276, - lessorsimilar = 0x2272, - maltesecross = 0xFFFD, - measuredangle = 0x2221, - muchgreater = 0x22D9, - muchless = 0x22D8, - multimap = 0x22B8, - multiopenleft = 0x22CB, - multiopenright = 0x22CC, - nand = 0x22BC, - orunderscore = 0x22BB, - perpcorrespond = 0x2259, - precedesorcurly = 0x227C, - precedesorequal = 0x227E, - primereverse = 0x2035, - proportional = 0x221D, - revasymptequal = 0x2243, - revsimilar = 0x223D, - rightanglene = 0x231D, - rightanglenw = 0x231C, - rightanglese = 0x231F, - rightanglesw = 0x231E, - ringinequal = 0x2256, - satisfies = 0x22A8, - shiftleft = 0x21B0, - shiftright = 0x21B1, - smile = 0x2323, - sphericalangle = 0x2222, - square = 0x25A1, - squaredot = 0x22A1, - squareimage = 0x228F, - squareminus = 0x229F, - squaremultiply = 0x22A0, - squareoriginal = 0x2290, - squareplus = 0x229E, - squaresmallsolid = 0x25AA, - squaresolid = 0x25A0, - squiggleleftright = 0x21AD, - squiggleright = 0x21DD, - star = 0x22C6, - subsetdbl = 0x22D0, - subsetdblequal = 0x2286, - supersetdbl = 0x22D1, - supersetdblequa = 0x2287, - therefore = 0x2234, - triangle = 0x25B5, - triangledownsld = 0x25BE, - triangleinv = 0x25BF, - triangleleft = 0x25C3, - triangleleftequal = 0x22B4, - triangleleftsld = 0x25C2, - triangleright = 0x25B9, - trianglerightequal = 0x22B5, - trianglerightsld = 0x25B8, - trianglesolid = 0x25B4, - uniondbl = 0x22D3, - uprise = 0x22CF, - Yen = 0x00A5, -} 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 ).

over a string.

--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--

It only makes sense to collapse at runtime, since we don't expect -source code to depend on collapsing:

- - -characters.filters.utf.collapsing = true -input.filters.utf_translator = characters.filters.utf.collapse - +source code to depend on collapsing.

--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--

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-- -

In the beginning of 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.

- - -utffilters.collapsing = true -characters.filters.append(utffilters.collapse) -characters.filters.activated = true -callback.register('process_input_buffer', characters.filters.process) - - -

The following helper functions may disappear (or become optional) -in the future. Well, they are now.

+

Next we implement some commands that are used in the user interface.

--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-- -

The following code is no longer needed and replaced by token -collectors somehwere else.

+

A few helpers (used to be luat-uni).

--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 { } + +--[[ +

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.

+]]-- + +-- 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.mkii b/tex/context/base/colo-ext.mkii new file mode 100644 index 000000000..06facd34e --- /dev/null +++ b/tex/context/base/colo-ext.mkii @@ -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-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-ext.tex b/tex/context/base/colo-ext.tex deleted file mode 100644 index 33e87459d..000000000 --- a/tex/context/base/colo-ext.tex +++ /dev/null @@ -1,57 +0,0 @@ -%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 @@ + + + + + + + + + <?lua pv('title') ?> + + + + +
+ +
+
+ +
+ +
+
+
+
+ +
+ + 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 @@ - - - <?lua pv('title') ?> - - - + + + + + <?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 @@ - - - <?lua pv('title') ?> - - - + + + + <?lua pv('title') ?> + + +
@@ -41,7 +46,6 @@ -

Scratch Variables

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 @@ - - - <?lua pv('title')?> - - - + + + + <?lua pv('title')?> + + +
@@ -40,7 +44,7 @@ File     Line     -
+
             
             
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 @@ + + + + + + + + + + <?lua pv('title')?> + + + + +
+
+ +
+
+ +
+ +
+ +
+
+ +
+
+ + 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 @@ + + + + + + + + + + <?lua pv('title') ?> + + + + +
+ +
+
+ +
+ +
+
+ +
+
+

+ +
+
+
+ +
+ + 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 @@ + + + + + + + + + + + + <?lua pv('title')?> + + + + +
+ +
+
+ +
+ +
+ +
+
+ +

+ +
+ +
+
+ + 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.lua b/tex/context/base/core-blk.lua deleted file mode 100644 index 1007273d5..000000000 --- a/tex/context/base/core-blk.lua +++ /dev/null @@ -1,145 +0,0 @@ -if not modules then modules = { } end modules ['core-blk'] = { - version = 1.001, - comment = "companion to core-blk.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- this one runs on top of buffers and structure - -local texprint, format = tex.print, string.format - -structure = structure or { } -structure.blocks = structure.blocks or { } - -local blocks = structure.blocks - -blocks.collected = blocks.collected or { } -blocks.tobesaved = blocks.tobesaved or { } -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 -end - --- not used, todo: option to do single or double pass - --- job.register('structure.blocks.collected', structure.blocks.tobesaved, initializer, nil) - -local printer = (lpeg.linebyline/texprint)^0 - -function blocks.print(name,data,hide) - if hide then - texprint(tex.ctxcatcodes,format("\\dostarthiddenblock{%s}",name)) - else - texprint(tex.ctxcatcodes,format("\\dostartnormalblock{%s}",name)) - end - if type(data) == "table" then - for i=1,#data do - texprint(data[i]) - end - else - printer:match(data) - end - if hide then - texprint(tex.ctxcatcodes,"\\dostophiddenblock") - else - texprint(tex.ctxcatcodes,"\\dostopnormalblock") - end -end - -function blocks.define(name) - states[name] = { all = "hide" } -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 - local sn = states[n] - if not sn then - -- error - elseif all then - sn.all = state - else - for _, tag in pairs(tags) do - sn[tag] = state - end - end - end -end - -function blocks.select(state,name,tag,criterium) - criterium = criterium or "text" - if tag:find("=") then tag = "" end - local names = aux.settings_to_set(name) - local all = tag == "" - 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) - for i=1,#result do - local b = result[i].entry - if names[b.name] then - local btags = b.tags - if all then - blocks.print(name,b.data,hide) - else - for tag, sta in pairs(tags) do - if btags[tag] then - blocks.print(name,b.data,hide) - break - end - end - end - end - end -end - -function blocks.save(name,tag,buffer) - 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 = { - name = name, - tags = tags, - data = data or "error", - plus = plus, - minus = minus, - }, - sectionnumber = slt[#slt] and slt[#slt].sectionnumber - } - local allstate = states[name].all - if not next(tags) then - if allstate ~= "hide" then - blocks.print(name,data) - elseif plus then - blocks.print(name,data,true) - end - else - local sn = states[name] - for tag, _ in pairs(tags) do - if sn[tag] == nil then - if allstate ~= "hide" then - blocks.print(name,data) - break - end - elseif sn[tag] ~= "hide" then - blocks.print(name,data) - break - end - end - 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/core-blk.mkiv deleted file mode 100644 index 9d1f4deb4..000000000 --- a/tex/context/base/core-blk.mkiv +++ /dev/null @@ -1,109 +0,0 @@ -%D \module -%D [ file=core-blk, -%D version=2008.10.20, -%D title=\CONTEXT\ Core Macros, -%D subtitle=Blockmoves, -%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-blk}{1.001} -\ctxloadluafile{core-blk}{} - -% we run on top of buffers and sections -% -% todo: prefix numbers (needs further integration elsewhere) -% check functionality -% alternative files (needs further integration elsewhere) - -\def\blockparameter#1#2{\ifcsname\??tb#1#2\endcsname\csname\??tb#1#2\endcsname\fi} - -\def\setupblockparameters{\dodoubleargument \dosetupblock} % fast one (for compatibility) -\def\setupblock {\dodoubleargumentwithset\dosetupblock} % handles set - -\def\dosetupblock[#1]{\getparameters[\??tb#1]} % [#1][#2]} - -\def\defineblock - {\dosingleargument\dodefineblock} - -\def\dodefineblock[#1]% - {\getparameters - [\??tb#1] - [\c!before=\blank, - \c!after=\blank, - \c!inner=, - \c!style=, - \c!file=]% todo - \ctxlua{structure.blocks.define("#1")}% - \setvalue{\e!begin#1}{\dodoubleempty\dobeginofblock[#1]}% - \letvalue{\e!end#1}\relax} - -\long\def\dobeginofblock[#1][#2]% - {\expanded{\dodowithbuffer{@block@}{\e!begin#1}{\e!end#1}} - {}{\ctxlua{structure.blocks.save("#1","#2","@block@")}}}% before after - -\def\dostarthiddenblock - {\startnointerference - \dostartnormalblock} - -\def\dostophiddenblock - {\dostopnormalblock - \stopnointerference} - -% order matters: \c!before (think of: \c!before=\startitemize) - -\let\doblocksetups\gobbleoneargument - -\def\dostartnormalblock#1% name - {\bgroup -\visibletrue - \edef\currentblock{#1}% - \doblocksetups\currentblock - \let\doblocksetups\gobbleoneargument - \blockparameter\currentblock\c!before - \dosetfontattribute{\??tb\currentblock}\c!style - \dosetcolorattribute{\??tb\currentblock}\c!color - \blockparameter\currentblock\c!inner - \ignorespaces} - -\def\dostopnormalblock - {\removeunwantedspaces - \blockparameter\currentblock\c!after - \par % todo: alternative = text, paragraph - \egroup} - -\def\dosetblockstate[#1][#2][#3]% state name tag - {\ctxlua{structure.blocks.setstate("#1","#2","#3")}} - -\def\doselectblocks[#1][#2][#3][#4]% state name tag setups - {\begingroup - \doifassignmentelse{#3} - {\getparameters[\??tb\??tb][\c!criterium=\v!text,#3]% - \def\doblocksetups##1{\getparameters[\??tb##1][#3]}% - \ctxlua{structure.blocks.select("#1","#2","","\@@tb@@tbcriterium")}} - {\getparameters[\??tb\??tb][\c!criterium=\v!text,#4]% - \def\doblocksetups##1{\getparameters[\??tb##1][#4]}% - \ctxlua{structure.blocks.select("#1","#2","#3","\@@tb@@tbcriterium")}}% - \endgroup} - -% hide: save, if [+] also hidden execute -% keep: save and normal execute - -\def\hideblocks{\dotripleempty\dosetblockstate[hide]} -\def\keepblocks{\dotripleempty\dosetblockstate[keep]} - -% use : normal execute unless [-] -% process: hidden execute unless [-] -% select : idem use - -\def\useblocks {\doquadrupleempty\doselectblocks[use]} -\def\processblocks{\doquadrupleempty\doselectblocks[process]} -\def\selectblocks {\doquadrupleempty\doselectblocks[use]} - -\protect 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.

Some code may move to a module in the language namespace.

--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-env.mkii b/tex/context/base/core-env.mkii new file mode 100644 index 000000000..a22594b27 --- /dev/null +++ b/tex/context/base/core-env.mkii @@ -0,0 +1,543 @@ +%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 + +% 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\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{\cleanuplabel{#1}\processcommacommand[\cleanlabel]\dosetups} % {..} +\def\dosetupsB[#1]{\cleanuplabel{#1}\processcommacommand[\cleanlabel]\dosetups} % [..] +\def\dosetupsC[#1]{\cleanuplabel{#1}\dosetups\cleanlabel} % [..] + +% \def\dosetups#1% the grid option will be extended to other main modes +% {\executeifdefined{\??su\ifgridsnapping\v!grid\fi:#1} +% {\executeifdefined{\??su :#1}\gobbleoneargument}\empty} % takes one argument +% +% \def\setupwithargument#1% the grid option will be extended to other main modes +% {\executeifdefined{\??su:#1}\gobbleoneargument} + +% better: + +% \def\dosetups#1% the grid option will be extended to other main modes +% {\executeifdefined{\??su\ifgridsnapping\v!grid\fi:#1} +% {\executeifdefined{\??su :#1}\gobbleoneargument}\empty} % takes one argument +% +% \def\setupwithargument#1% the grid option will be extended to other main modes +% {\executeifdefined{\??su:#1}\gobbleoneargument} + +% faster: + +\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 + +% somehow fails ... +% +% \letvalue{\??su:..}\gobbleoneargument +% +% \def\dosetups#1% the grid option will be extended to other main modes +% {\csname \??su +% \ifcsname\??su\ifgridsnapping\v!grid\fi:#1\endcsname\v!grid:#1\else +% \ifcsname\??su :#1\endcsname :#1\else +% :..\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..\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\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 + \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% watch out: not \grabuntil +% {\dograbuntil#1{\endgroup\dodoglobal\long\setvalue{\??su#2:#3}}} % \doglobal +% +% better: + +% \long\def\dodostartsetups#1#2#3% watch out: not \grabuntil +% {\cleanuplabel{\??su#2:#3}\dograbuntil#1{\endgroup\dodoglobal\long\setvalue\cleanlabel}} % \doglobal + +% \long\def\dodostartsetups#1#2#3% +% {\cleanuplabel{\??su#2:#3}% +% \long\def\dododostartsetups##1#1{\endgroup\dodoglobal\long\setvalue\cleanlabel####1{##1}}\dododostartsetups} + +\long\def\dodostartsetups#1#2#3% + {\cleanuplabel{\??su#2:#3}% + \long\def\dododostartsetups##1#1% + {\endgroup + \dodoglobal % bah + \long\expandafter\setvalue\expandafter\cleanlabel\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 + {\ifundefined{\??su\ifgridsnapping\v!grid\fi:#1}% + \dodoglobal\letbeundefined{\??su:#1}% + \else + \dodoglobal\letbeundefined{\??su\ifgridsnapping\v!grid\fi:#1}% + \fi} + +% or +% +% \def\resetsetups[#1]% +% {\letbeundefined +% {\??su:% +% \ifundefined{\??su\ifgridsnapping\v!grid\fi:#1}#1\else\ifgridsnapping\v!grid\fi% +% #1}} + +%D new and beta and will become a module instead + +\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} % + \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 \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 test +%D test test +%D test test +%D test test +%D zus<>zo zus<:>zo zus<::>zo +%D test test dat (ziezo) +%D test test dat (:ziezo) +%D test test dat (ziezo:) +%D test test dat (zi:ezo:) +%D well, 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 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 + +%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 +% \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 + +\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-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 test +%D test test +%D test test +%D test test +%D zus<>zo zus<:>zo zus<::>zo +%D test test dat (ziezo) +%D test test dat (:ziezo) +%D test test dat (ziezo:) +%D test test dat (zi:ezo:) +%D well, 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 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.mkii b/tex/context/base/core-fld.mkii new file mode 100644 index 000000000..2b177c916 --- /dev/null +++ b/tex/context/base/core-fld.mkii @@ -0,0 +1,1080 @@ +%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% + {\checkobjectreferences + \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-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-fld.tex b/tex/context/base/core-fld.tex deleted file mode 100644 index 3b1ce9b3f..000000000 --- a/tex/context/base/core-fld.tex +++ /dev/null @@ -1,1080 +0,0 @@ -%D \module -%D [ file=core-fld, -%D version=1997.05.18, -%D title=\CONTEXT\ Core Macros, -%D subtitle=Fill in 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 Field Macros} - -% 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% - {\checkobjectreferences - \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.mkii b/tex/context/base/core-fnt.mkii new file mode 100644 index 000000000..9bc2a66f5 --- /dev/null +++ b/tex/context/base/core-fnt.mkii @@ -0,0 +1,726 @@ +%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 {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}. + +\def\usepseudocaps + {\def\cap@@uppercase{\the\everyuppercase\uppercased}% + \def\cap@@lowercase{\the\everylowercase\lowercased}% + \def\cap@@visualize{\tx}} + +\def\userealcaps + {\let\cap@@uppercase\relax + %\let\cap@@lowercase\relax % Definitely not! + \def\cap@@visualize{\sc}} + +\usepseudocaps + +\unexpanded\def\smallcapped % else conflict with math + {\futurelet\next\dosmallcapped} + +\def\disablepseudocaps + {\let\smallcapped\donothing} + +\def\dosmallcapped + {\ifx\next\bgroup + \expandafter\dodosmallcapped\expandafter\relax + \else + \expandafter\dodosmallcapped + \fi} + +\def\dodosmallcapped#1#2% + {\ifmmode\hbox\fi + \bgroup + \cap@@visualize + \cap@@uppercase{#1{#2}}% + \egroup} + +\unexpanded\def\notsmallcapped#1% + {\cap@@lowercase{#1}} + +\unexpanded\def\CAPPED#1% + {{\def\\##1{\smallcapped{##1}}#1}} + +\unexpanded\def\SmallCapped#1% + {\CAPPED{\\#1}} + +\unexpanded\def\SmallCaps + {\let\processword\SmallCapped + \processwords} + +%D Sure: + +\def\kap{\smallcapped} % for old times sake + +%D Some precautions for a \PLAIN\ \TEX\ definition. + +\unexpanded\def\normalcap{\dohandlemathtoken{cap}} +\unexpanded\def\normalCap{\dohandlemathtoken{Cap}} + +\def\cap{\mathortext\normalcap\smallcapped} +\def\Cap{\mathortext\normalCap\SmallCapped} + +\appendtoks + \let\cap\firstofoneargument + \let\Cap\firstofoneargument +\to \simplifiedcommands + +%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]% + \unexpanded\def\smallcapped{\normalsmallcapped}} + {\definealternativestyle[\v!capital][\normalsmallcapped][\uppercased]% + \definealternativestyle[\v!smallcaps][\sc][\uppercased]% + \unexpanded\def\smallcapped{\doconvertfont\v!capital}}% + \doifelse\@@kksc\v!yes + \userealcaps + \usepseudocaps} + +\ifx\uppercased\undefined \let\uppercased\uppercase \fi +\ifx\lowercased\undefined \let\lowercased\lowercase \fi + +% pretty tricky stuff: +% +% \usemodule[abr-01] \TEX \METAPOST \PPCHTEX \LATEX +% \usemodule[abr-02] \TEX \METAPOST \PPCHTEX \LATEX + +%def\uppercased#1{{\forceunexpanded\xdef\@@globalcrap{\uppercase{#1}}}\@@globalcrap} +%def\lowercased#1{{\forceunexpanded\xdef\@@globalcrap{\lowercase{#1}}}\@@globalcrap} + +\def\uppercased#1{{\forceunexpanded\xdef\@@expanded{\uppercase{#1}}}\@@expanded} +\def\lowercased#1{{\forceunexpanded\xdef\@@expanded{\lowercase{#1}}}\@@expanded} + +\setupcapitals + [\c!title=\v!yes, + \c!sc=\v!no] + +%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\doWord#1% + {\bgroup + \the\everyuppercase + \uppercase{#1}% + \egroup} + +\unexpanded\def\Word#1% + {\doWord#1} + +\def\doprocesswords#1 #2\od + {\ConvertToConstant\doifnot{#1}{} + {\processword{#1} % + \doprocesswords#2 \od}} + +\def\processwords#1% + {\doprocesswords#1 \od\unskip} + +\let\processword\relax + +\unexpanded\def\Words + {\let\processword\Word + \processwords} + +\unexpanded\def\WORD#1% + {\bgroup + \let\smallcapped\firstofoneargument + \let\WORD\firstofoneargument + \douppercase{#1}% + \egroup} + +\unexpanded\def\WORDS#1% + {\WORD{#1}} + +%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} +%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#1#2% +% {\dontleavehmode +% \hbox +% {\setbox4=\hbox{\dohighlow\lower\mathsubnormal{.48}{.1}{#1}}% +% \setbox6=\hbox{\dohighlow\raise\mathsupnormal{.86}{.1}{#2}}% +% \ifdim\wd4<\wd6 +% \wd4=\zeropoint\box4\box6 +% \else +% \wd6=\zeropoint\box6\box4 +% \fi}} + +\unexpanded\def\lohi + {\dosingleempty\dolohi} + +\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}} + +%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-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-fnt.tex b/tex/context/base/core-fnt.tex deleted file mode 100644 index e6f7fada4..000000000 --- a/tex/context/base/core-fnt.tex +++ /dev/null @@ -1,726 +0,0 @@ -%D \module -%D [ file=core-fnt, -%D version=1995.10.10, -%D title=\CONTEXT\ Core Macros, -%D subtitle=Font 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. - -\writestatus{loading}{Context Core Macros / Font Support} - -\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 {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}. - -\def\usepseudocaps - {\def\cap@@uppercase{\the\everyuppercase\uppercased}% - \def\cap@@lowercase{\the\everylowercase\lowercased}% - \def\cap@@visualize{\tx}} - -\def\userealcaps - {\let\cap@@uppercase\relax - %\let\cap@@lowercase\relax % Definitely not! - \def\cap@@visualize{\sc}} - -\usepseudocaps - -\unexpanded\def\smallcapped % else conflict with math - {\futurelet\next\dosmallcapped} - -\def\disablepseudocaps - {\let\smallcapped\donothing} - -\def\dosmallcapped - {\ifx\next\bgroup - \expandafter\dodosmallcapped\expandafter\relax - \else - \expandafter\dodosmallcapped - \fi} - -\def\dodosmallcapped#1#2% - {\ifmmode\hbox\fi - \bgroup - \cap@@visualize - \cap@@uppercase{#1{#2}}% - \egroup} - -\unexpanded\def\notsmallcapped#1% - {\cap@@lowercase{#1}} - -\unexpanded\def\CAPPED#1% - {{\def\\##1{\smallcapped{##1}}#1}} - -\unexpanded\def\SmallCapped#1% - {\CAPPED{\\#1}} - -\unexpanded\def\SmallCaps - {\let\processword\SmallCapped - \processwords} - -%D Sure: - -\def\kap{\smallcapped} % for old times sake - -%D Some precautions for a \PLAIN\ \TEX\ definition. - -\unexpanded\def\normalcap{\dohandlemathtoken{cap}} -\unexpanded\def\normalCap{\dohandlemathtoken{Cap}} - -\def\cap{\mathortext\normalcap\smallcapped} -\def\Cap{\mathortext\normalCap\SmallCapped} - -\appendtoks - \let\cap\firstofoneargument - \let\Cap\firstofoneargument -\to \simplifiedcommands - -%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]% - \unexpanded\def\smallcapped{\normalsmallcapped}} - {\definealternativestyle[\v!capital][\normalsmallcapped][\uppercased]% - \definealternativestyle[\v!smallcaps][\sc][\uppercased]% - \unexpanded\def\smallcapped{\doconvertfont\v!capital}}% - \doifelse\@@kksc\v!yes - \userealcaps - \usepseudocaps} - -\ifx\uppercased\undefined \let\uppercased\uppercase \fi -\ifx\lowercased\undefined \let\lowercased\lowercase \fi - -% pretty tricky stuff: -% -% \usemodule[abr-01] \TEX \METAPOST \PPCHTEX \LATEX -% \usemodule[abr-02] \TEX \METAPOST \PPCHTEX \LATEX - -%def\uppercased#1{{\forceunexpanded\xdef\@@globalcrap{\uppercase{#1}}}\@@globalcrap} -%def\lowercased#1{{\forceunexpanded\xdef\@@globalcrap{\lowercase{#1}}}\@@globalcrap} - -\def\uppercased#1{{\forceunexpanded\xdef\@@expanded{\uppercase{#1}}}\@@expanded} -\def\lowercased#1{{\forceunexpanded\xdef\@@expanded{\lowercase{#1}}}\@@expanded} - -\setupcapitals - [\c!title=\v!yes, - \c!sc=\v!no] - -%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\doWord#1% - {\bgroup - \the\everyuppercase - \uppercase{#1}% - \egroup} - -\unexpanded\def\Word#1% - {\doWord#1} - -\def\doprocesswords#1 #2\od - {\ConvertToConstant\doifnot{#1}{} - {\processword{#1} % - \doprocesswords#2 \od}} - -\def\processwords#1% - {\doprocesswords#1 \od\unskip} - -\let\processword\relax - -\unexpanded\def\Words - {\let\processword\Word - \processwords} - -\unexpanded\def\WORD#1% - {\bgroup - \let\smallcapped\firstofoneargument - \let\WORD\firstofoneargument - \douppercase{#1}% - \egroup} - -\unexpanded\def\WORDS#1% - {\WORD{#1}} - -%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} -%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#1#2% -% {\dontleavehmode -% \hbox -% {\setbox4=\hbox{\dohighlow\lower\mathsubnormal{.48}{.1}{#1}}% -% \setbox6=\hbox{\dohighlow\raise\mathsupnormal{.86}{.1}{#2}}% -% \ifdim\wd4<\wd6 -% \wd4=\zeropoint\box4\box6 -% \else -% \wd6=\zeropoint\box6\box4 -% \fi}} - -\unexpanded\def\lohi - {\dosingleempty\dolohi} - -\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}} - -%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.mkii b/tex/context/base/core-int.mkii new file mode 100644 index 000000000..1ca9d23d1 --- /dev/null +++ b/tex/context/base/core-int.mkii @@ -0,0 +1,2217 @@ +%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} + +%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} + +\def\@@bookmark {bm::} +\def\@@booklevel{bl::} +\def\@@bookcount{bc::} + +\definelist[\@@bookmark] + +\newtoks\postponedbookmarks + +\def\flushpostponedbookmark + {\the\postponedbookmarks + \global\postponedbookmarks\emptytoks} + +\def\simplebookmark#1% + {\doglobal\prependtoks + \writetolist[\@@bookmark]{}{#1}% + \to\postponedbookmarks} + +\def\complexbookmark[#1]#2% + {\doglobal\appendtoks\writetolist[#1]{}{#2}\to\postponedbookmarks} + +\definecomplexorsimple\bookmark + +\newif\iftracebookmarks \tracebookmarksfalse + +\let\tracebookmarks\tracebookmarkstrue + +\def\placebookmarks + {\dodoubleempty\doplacebookmarks} + +\def\doplacebookmarks[#1][#2]% + {\iflocation + \iffirstargument + \bgroup + \ifsecondargument + \doifelse{#2}\v!all + {\edef\openbookmarklist{#1}} + {\edef\openbookmarklist{#2}}% + \else + \let\openbookmarklist\empty + \fi + \global\let\bookmarklevellist\empty + \def\bookmarklevelcount{0}% + \doprocessbookmarks[#1]\dogetbookmarkelement + \dolistelement{}{}{}{}{}{}% needed to finish the first pass + \doprocessbookmarks[#1]\doputbookmarkelement + \flushbookmark + \egroup + \else + \expanded{\placebookmarks\@EA[\getvalue{\??ih\v!content\c!list}]}% + \fi + \fi} + +\def\doprocessbookmarks[#1]#2% + {\let\dolistelement#2\relax + \scratchcounter\zerocount + \def\docommand##1% + {\advance\scratchcounter \plusone + \getlistlevel[##1]\listlevel{\the\scratchcounter}% + \setxvalue{\@@bookcount\the\scratchcounter}{1}% + \setxvalue{\@@booklevel##1}{\listlevel}}% + \processcommalist[#1]\docommand + \setxvalue{\@@bookcount0}{1}% + \global\chardef\currentbookmarklevel\zerocount + \global\chardef\previousbookmarklevel\zerocount + \doutilities{listentries,#1,\@@bookmark}\jobname{#1}\relax\relax} + +\def\dodogetbookmarkelement#1#2#3#4#5#6% + {\doifelsenothing{#1} + {\global\chardef\currentbookmarklevel\zerocount} + {\global\chardef\currentbookmarklevel\getvalue{\@@booklevel#1}\relax}% + \ifnum\currentbookmarklevel>\previousbookmarklevel + \setxvalue{\@@bookcount\the\currentbookmarklevel}{1}% + \else\ifnum\currentbookmarklevel<\previousbookmarklevel + \bgroup + \!!counta\previousbookmarklevel + \doloop + {\let\bookmarktag\empty + \!!countb\!!counta + \advance\!!countb \minusone + \dorecurse\!!countb + {\edef\bookmarktag + {\bookmarktag\getvalue{\@@bookcount\recurselevel}:}}% + \edef\bookmarklevelcount + {\getvalue{\@@bookcount\the\!!counta}}% + \xdef\bookmarklevellist + {\bookmarklevellist/\bookmarktag:\bookmarklevelcount/}% + \advance\!!counta \minusone + \ifnum\!!counta=\currentbookmarklevel + \exitloop + \fi}% + \egroup + \@EA\doglobal\@EA\increment\csname \@@bookcount\the\currentbookmarklevel\endcsname\relax + \else + \@EA\doglobal\@EA\increment\csname \@@bookcount\the\previousbookmarklevel\endcsname\relax + \fi\fi + \global\utilitydonetrue + \global\chardef\previousbookmarklevel\currentbookmarklevel} + +\def\getbookmarklevelcount + {\@EA\def\@EA\docommand\@EA[\@EA##\@EA1\@EA/\bookmarktag:##2/##3]% + {\def\bookmarklevelcount{##2}}% + \@EA\@EA\@EA\docommand\@EA\@EA\@EA[\@EA\bookmarklevellist\@EA/\bookmarktag:0/]} + +\def\dodoputbookmarkelement#1#2#3#4#5#6% + {\doifelsenothing{#1} + {\global\chardef\currentbookmarklevel\zerocount} + {\global\chardef\currentbookmarklevel\getvalue{\@@booklevel#1}\relax}% + \ifnum\currentbookmarklevel>\previousbookmarklevel + \setxvalue{\@@bookcount\the\currentbookmarklevel}{1}% + \else\ifnum\currentbookmarklevel<\previousbookmarklevel + \@EA\doglobal\@EA\increment\csname \@@bookcount\the\currentbookmarklevel\endcsname\relax + \else + \@EA\doglobal\@EA\increment\csname \@@bookcount\the\previousbookmarklevel\endcsname\relax + \fi\fi + \let\bookmarktag\empty + \!!countb\currentbookmarklevel + \dorecurse\!!countb + {\edef\bookmarktag + {\bookmarktag\getvalue{\@@bookcount\recurselevel}:}}% + \getbookmarklevelcount + \iftracebookmarks + \bgroup + \par + \bookmarktag\quad + \dorecurse\currentbookmarklevel{\quad}\unskip#1\quad + (\bookmarklevelcount)\quad + \egroup + \fi + \global\chardef\previousbookmarklevel\currentbookmarklevel + \global\utilitydonetrue + \insertsomebookmark{#1}{\the\currentbookmarklevel}{\bookmarklevelcount}{#4}{#6}} + +\def\dogetbookmarkelement#1#2#3#4#5#6% + {\doifnot{#1}\@@bookmark + {\dodogetbookmarkelement{#1}{#2}{#3}{#4}{#5}{#6}}} + +\def\doputbookmarkelement#1#2#3#4#5#6% + {\doifelse{#1}\@@bookmark + {\localbookmark{#4}} + {\flushbookmark + \dodoputbookmarkelement{#1}{#2}{#3}{#4}{#5}{#6}}} + +\let\flushbookmark\relax +\let\localbookmark\gobbleoneargument + +\def\insertsomebookmark#1#2#3#4#5% + {\gdef\flushbookmark + {\doinsertsomebookmark{#1}{#2}{#3}{#4}{#5}{g}}% + \gdef\localbookmark##1% + {\doinsertsomebookmark{#1}{#2}{#3}{##1}{#5}{l}}} + +\def\doinsertsomebookmark#1#2#3#4#5#6% + {\global\utilitydonetrue + \global\let\localbookmark\gobbleoneargument + \global\let\flushbookmark\relax + \doifinstringelse{#1}\openbookmarklist + {\chardef\openbookmark\plusone} + {\chardef\openbookmark\zerocount}% + \iftracebookmarks(#6: #4)\quad(\the\openbookmark)\par\fi + \doinsertbookmark{#2}{#3}{#4}{#5}{\openbookmark}} + +% \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 ! + {\checkreferences % nodig ?? + \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-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-int.tex b/tex/context/base/core-int.tex deleted file mode 100644 index 79061958d..000000000 --- a/tex/context/base/core-int.tex +++ /dev/null @@ -1,2355 +0,0 @@ -%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} - -% 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 - -\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} - -%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} - -\def\@@bookmark {bm::} -\def\@@booklevel{bl::} -\def\@@bookcount{bc::} - -\definelist[\@@bookmark] - -\newtoks\postponedbookmarks - -\def\flushpostponedbookmark - {\the\postponedbookmarks - \global\postponedbookmarks\emptytoks} - -\def\simplebookmark#1% - {\doglobal\prependtoks - \writetolist[\@@bookmark]{}{#1}% - \to\postponedbookmarks} - -\def\complexbookmark[#1]#2% - {\doglobal\appendtoks\writetolist[#1]{}{#2}\to\postponedbookmarks} - -\definecomplexorsimple\bookmark - -\newif\iftracebookmarks \tracebookmarksfalse - -\let\tracebookmarks\tracebookmarkstrue - -\def\placebookmarks - {\dodoubleempty\doplacebookmarks} - -\def\doplacebookmarks[#1][#2]% - {\iflocation - \iffirstargument - \bgroup - \ifsecondargument - \doifelse{#2}\v!all - {\edef\openbookmarklist{#1}} - {\edef\openbookmarklist{#2}}% - \else - \let\openbookmarklist\empty - \fi - \global\let\bookmarklevellist\empty - \def\bookmarklevelcount{0}% - \doprocessbookmarks[#1]\dogetbookmarkelement - \dolistelement{}{}{}{}{}{}% needed to finish the first pass - \doprocessbookmarks[#1]\doputbookmarkelement - \flushbookmark - \egroup - \else - \expanded{\placebookmarks\@EA[\getvalue{\??ih\v!content\c!list}]}% - \fi - \fi} - -\def\doprocessbookmarks[#1]#2% - {\let\dolistelement#2\relax - \scratchcounter\zerocount - \def\docommand##1% - {\advance\scratchcounter \plusone - \getlistlevel[##1]\listlevel{\the\scratchcounter}% - \setxvalue{\@@bookcount\the\scratchcounter}{1}% - \setxvalue{\@@booklevel##1}{\listlevel}}% - \processcommalist[#1]\docommand - \setxvalue{\@@bookcount0}{1}% - \global\chardef\currentbookmarklevel\zerocount - \global\chardef\previousbookmarklevel\zerocount - \doutilities{listentries,#1,\@@bookmark}\jobname{#1}\relax\relax} - -\def\dodogetbookmarkelement#1#2#3#4#5#6% - {\doifelsenothing{#1} - {\global\chardef\currentbookmarklevel\zerocount} - {\global\chardef\currentbookmarklevel\getvalue{\@@booklevel#1}\relax}% - \ifnum\currentbookmarklevel>\previousbookmarklevel - \setxvalue{\@@bookcount\the\currentbookmarklevel}{1}% - \else\ifnum\currentbookmarklevel<\previousbookmarklevel - \bgroup - \!!counta\previousbookmarklevel - \doloop - {\let\bookmarktag\empty - \!!countb\!!counta - \advance\!!countb \minusone - \dorecurse\!!countb - {\edef\bookmarktag - {\bookmarktag\getvalue{\@@bookcount\recurselevel}:}}% - \edef\bookmarklevelcount - {\getvalue{\@@bookcount\the\!!counta}}% - \xdef\bookmarklevellist - {\bookmarklevellist/\bookmarktag:\bookmarklevelcount/}% - \advance\!!counta \minusone - \ifnum\!!counta=\currentbookmarklevel - \exitloop - \fi}% - \egroup - \@EA\doglobal\@EA\increment\csname \@@bookcount\the\currentbookmarklevel\endcsname\relax - \else - \@EA\doglobal\@EA\increment\csname \@@bookcount\the\previousbookmarklevel\endcsname\relax - \fi\fi - \global\utilitydonetrue - \global\chardef\previousbookmarklevel\currentbookmarklevel} - -\def\getbookmarklevelcount - {\@EA\def\@EA\docommand\@EA[\@EA##\@EA1\@EA/\bookmarktag:##2/##3]% - {\def\bookmarklevelcount{##2}}% - \@EA\@EA\@EA\docommand\@EA\@EA\@EA[\@EA\bookmarklevellist\@EA/\bookmarktag:0/]} - -\def\dodoputbookmarkelement#1#2#3#4#5#6% - {\doifelsenothing{#1} - {\global\chardef\currentbookmarklevel\zerocount} - {\global\chardef\currentbookmarklevel\getvalue{\@@booklevel#1}\relax}% - \ifnum\currentbookmarklevel>\previousbookmarklevel - \setxvalue{\@@bookcount\the\currentbookmarklevel}{1}% - \else\ifnum\currentbookmarklevel<\previousbookmarklevel - \@EA\doglobal\@EA\increment\csname \@@bookcount\the\currentbookmarklevel\endcsname\relax - \else - \@EA\doglobal\@EA\increment\csname \@@bookcount\the\previousbookmarklevel\endcsname\relax - \fi\fi - \let\bookmarktag\empty - \!!countb\currentbookmarklevel - \dorecurse\!!countb - {\edef\bookmarktag - {\bookmarktag\getvalue{\@@bookcount\recurselevel}:}}% - \getbookmarklevelcount - \iftracebookmarks - \bgroup - \par - \bookmarktag\quad - \dorecurse\currentbookmarklevel{\quad}\unskip#1\quad - (\bookmarklevelcount)\quad - \egroup - \fi - \global\chardef\previousbookmarklevel\currentbookmarklevel - \global\utilitydonetrue - \insertsomebookmark{#1}{\the\currentbookmarklevel}{\bookmarklevelcount}{#4}{#6}} - -\def\dogetbookmarkelement#1#2#3#4#5#6% - {\doifnot{#1}\@@bookmark - {\dodogetbookmarkelement{#1}{#2}{#3}{#4}{#5}{#6}}} - -\def\doputbookmarkelement#1#2#3#4#5#6% - {\doifelse{#1}\@@bookmark - {\localbookmark{#4}} - {\flushbookmark - \dodoputbookmarkelement{#1}{#2}{#3}{#4}{#5}{#6}}} - -\let\flushbookmark\relax -\let\localbookmark\gobbleoneargument - -\def\insertsomebookmark#1#2#3#4#5% - {\gdef\flushbookmark - {\doinsertsomebookmark{#1}{#2}{#3}{#4}{#5}{g}}% - \gdef\localbookmark##1% - {\doinsertsomebookmark{#1}{#2}{#3}{##1}{#5}{l}}} - -\def\doinsertsomebookmark#1#2#3#4#5#6% - {\global\utilitydonetrue - \global\let\localbookmark\gobbleoneargument - \global\let\flushbookmark\relax - \doifinstringelse{#1}\openbookmarklist - {\chardef\openbookmark\plusone} - {\chardef\openbookmark\zerocount}% - \iftracebookmarks(#6: #4)\quad(\the\openbookmark)\par\fi - \doinsertbookmark{#2}{#3}{#4}{#5}{\openbookmark}} - -% \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 ! - {\checkreferences % nodig ?? - \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\box\voidb@x}% - {\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-ltb.tex b/tex/context/base/core-ltb.tex deleted file mode 100644 index 3ebd16379..000000000 --- a/tex/context/base/core-ltb.tex +++ /dev/null @@ -1,856 +0,0 @@ -%D \module -%D [ file=core-ltb, -%D version=2002.10.31, -%D title=\CONTEXT\ Core Macros, -%D subtitle=Line 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. - -% testfile: tfmetrics.tex - -% todo: als nx>1, dan in geval van rek tussenruimte berekenen en optellen -% bij breedte, dus: nx nog niet gebruiken in combinatie met rek ! ! ! ! ! - -% This module is experimental, undocumented, and currently only set up -% eTeX. It provides a mechanism for typesetting very large tables, -% spanning many pages horizontally and vertically, with repeated -% header lines and (entry) columns, tab tracking, color, etc. In does -% two passes over a table, which is why the table goes into a -% buffer or file. As said, tables can be real huge. - -% \BH \BC .. \EC \BC .. \EC \EH % append -% \BR \BC .. \EC \BC .. \EC \ER -% -% or -% -% \NC .. \NC .. \NC \NR (todo: optional last \NC) - -% alternative: -% -% (1) direct run, save content in macro, but only if needed -% -% todo -% -% (2) buffered table content -% -% \startbuffer -% \startlinetablehead -% \stoplinetablehead -% \startlinetablebody -% \stoplinetablebody -% \stopbuffer -% -% \processlinetablebuffer[buffer] -% -% in buffer : head and body -% -% (3) unbuffered run, multipass -% -% - run with starting width zero / prev run -% - clip on prev run -% - flush real widths - -\writestatus{loading}{Context Core Macros / Line Tables} - -\unprotect - -\chardef\linetablesplitstate\zerocount -\chardef\linetableheadstate \zerocount - -\edef\??ler{\??le:r:} -\edef\??lec{\??le:c:} -\edef\??lew{\??le:w:} -\edef\??leh{\??le:h:} -\edef\??led{\??le:d:} - -\newif\iflinetablepreroll -\newif\ifinlinetable - -\newcount\linetablecolumn -\newcount\linetablesubcol -\newdimen\linetablewidth -\newdimen\linetableheight -\newbox \linetablecell - -\let\noflinetablecolumns\!!zerocount -\let\noflinetablerows \!!zerocount -\let\noflinetablelines \!!zerocount -\let\noflinetableparts \!!zerocount -\let\linetablepart \!!plusone -\let\linetablestep \!!plusone -\let\linetableline \!!zerocount -\let\linetablerow \!!zerocount -\let\linetablerows \!!zerocount - -\initializetablebox \zerocount % holds repeater - -\chardef\linetablehmode \zerocount -\chardef\linetablepage \zerocount -\chardef\linetablerepeat\zerocount - -\def\setuplinetable - {\dotripleempty\dosetuplinetable} - -\def\dosetuplinetable[#1][#2][#3]% - {\ifthirdargument - \getparameters[\??le:#1:#2][#3]% - \else\ifsecondargument - \getparameters[\??lec#1][#2]% - \else - \getparameters[\??le][#1]% - \fi\fi} - -\setuplinetable - [\c!n=\!!maxcard, - \c!lines=\!!maxcard, - \c!nx=\plusone, - \c!nleft=0, - \c!repeat=\v!yes, % when \c!nleft>0, repeat on both pages - \c!before=, - \c!after=, - \c!inbetween=\page, - \c!distance=\zeropoint, - \c!stretch=\v!no, - \c!align=\c!right, - \c!leftoffset=.25ex, - \c!rightoffset=\linetableparameter\c!leftoffset, - \c!maxwidth=\zeropoint, - \c!width=5em, - \c!height=\v!fit, % \v!line = faster - \c!background=, - \c!backgroundcolor=] - -\def\linetableparameter#1% - {\csname\??le#1\endcsname} - -\def\doifelselinetablecparameter#1% - {\ifcsname\??lec\number\linetablecolumn#1\endcsname - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\def\linetablecparameter#1% - {\csname - \ifcsname\??lec\number\linetablecolumn#1\endcsname - \??lec\number\linetablecolumn - \else - \??le - \fi - #1\endcsname} - -\def\linetablerparameter#1% faster, leaner and meaner - {\csname - \ifnum\linetablerow=\zerocount % geen ifcase - \ifcsname\??ler\v!header#1\endcsname - \??ler\v!header#1% - \else\ifcsname\??ler0#1\endcsname - \??ler0#1% - \else - \s!empty - \fi\fi - \else - \ifcsname\??ler\number\linetablerow#1\endcsname - \??ler\number\linetablerow#1% - \else\ifcsname\??ler\v!oddeven\linetablerow#1\endcsname - \??ler\v!oddeven\linetablerow#1% - \else - \s!empty - \fi\fi - \fi - \endcsname} - -\def\setnoftableslines - {\doifelse{\linetableparameter\c!lines}\v!fit - {% whitespace already added by vertical strut - \ifdim\pagegoal<\maxdimen - \scratchdimen\pagegoal - \advance\scratchdimen -\pagetotal - \else - \scratchdimen\textheight - \fi - \getrawnoflines\scratchdimen - \xdef\noflinetablelines{\the\noflines} -\iflinetablepreroll \else \ifnum\noflinetablelines<\plustwo - \page \setnoftableslines -\fi \fi -} - {\xdef\noflinetablelines{\linetableparameter\c!lines}}} - -\def\startlinetablecell - {\dosingleempty\dostartlinetablecell} - -\def\dostartlinetablecell[#1]% - {\global\setbox\linetablecell\hbox\bgroup - \iffirstargument - \getparameters[\??lec\number\linetablecolumn][#1]% - \fi - \xdef\linetablestep{\linetablecparameter\c!nx}% - \ifcase\linetablestep\or - \scratchdimen\linetablecparameter\c!width - \scratchskip \linetablecparameter\c!distance - \else - \scratchdimen \zeropoint - \scratchskip \zeropoint - \scratchcounter\linetablecolumn - \dorecurse\linetablestep - {\advance\scratchdimen\linetablecparameter\c!width - %\advance\scratchskip \linetablecparameter\c!distance - \global\advance \linetablecolumn\plusone - \advance\scratchskip \linetablecparameter\c!distance - }% - \global\linetablecolumn\scratchcounter - \fi - \chardef\linetablemode - \iflinetablepreroll - \ifdim\scratchdimen>\zeropoint \zerocount \else \plustwo \fi - \else - \zerocount - \fi - \ifcase\linetablemode - \ifcase\linetablehmode - % nothing - \or - % fit, keep it simple - \or - \chardef\linetablemode\plusone % line - \else - % some already calculated height - \fi - \fi - \setbox\scratchbox\hbox - \bgroup - \dontcomplain - \hskip\linetablecparameter\c!leftoffset\relax - % 0 = width, unknown height - % 1 = width, fixed height - % 2 = no width, auto hsize - \ifnum\linetablemode<\plustwo - \advance\scratchdimen-\linetablecparameter\c!leftoffset - \advance\scratchdimen-\linetablecparameter\c!rightoffset - \fi - \ifcase\linetablemode - \dosetraggedcommand{\linetablecparameter\c!align}% - \vtop \ifdim\linetableheight>\zeropoint to\linetableheight \fi \bgroup - \hsize\scratchdimen - \raggedcommand - \else - \setalignmentswitch{\linetablecparameter\c!align}% - \hbox \ifcase\linetablemode \or to\scratchdimen \fi \bgroup - \ifcase\alignmentswitch\hss\or\hss\fi - \fi - \dostartattributes{\??lec\number\linetablecolumn}\c!style\c!color\empty - \begstrut \ignorespaces} - -% \def\stoplinetablecell -% {\unskip \endstrut -% \dostopattributes -% \ifcase\linetablemode -% \endgraf -% \else -% \ifcase\alignmentswitch\else\hss\fi -% \fi -% \egroup -% \hskip\linetablecparameter\c!rightoffset -% \egroup -% \iflinetablepreroll -% \box\scratchbox -% \else -% \doif{\linetablecparameter\c!background}\v!color -% {\backgroundline[\linetablecparameter\c!backgroundcolor]}% -% {\box\scratchbox}% -% \fi -% \egroup} - -\newconditional\linetableautoheight \settrue\linetableautoheight - -\def\stoplinetablecell - {\unskip \endstrut - \dostopattributes - \ifcase\linetablemode - \endgraf - \else - \ifcase\alignmentswitch\else\hss\fi - \fi - \egroup - \hskip\linetablecparameter\c!rightoffset - \egroup - \iflinetablepreroll - \box\scratchbox - \else - \doifelse{\linetablecparameter\c!background}\v!color - {\ifconditional\linetableautoheight - \hbox{\blackrule - [ \c!color=\linetablecparameter\c!backgroundcolor, - \c!height=\linetablerparameter{x\c!height}, - \c!depth=\linetablerparameter{x\c!depth}, - \c!width=\wd\scratchbox]% - \hskip-\wd\scratchbox\box\scratchbox}% - \else - \backgroundline[\linetablecparameter\c!backgroundcolor]{\box\scratchbox}% - \fi}% - {\box\scratchbox}% - \fi - \egroup} - -% \def\stoplinetablecell -% {\unskip \endstrut -% \dostopattributes -% \ifcase\linetablemode -% \endgraf -% \else -% \ifcase\alignmentswitch\else\hss\fi -% \fi -% \egroup -% \hskip\linetablecparameter\c!rightoffset -% \egroup -% \iflinetablepreroll -% \box\scratchbox -% \else -% \doifelse{\linetablecparameter\c!background}\v!color -% {\ifconditional\linetableautoheight -% % \hbox{\blackrule -% % [ \c!color=\linetablecparameter\c!backgroundcolor, -% % \c!height=\linetablerparameter{x\c!height}, -% % \c!depth=\linetablerparameter{x\c!depth}, -% % \c!width=\wd\scratchbox]% -% % \hskip-\wd\scratchbox\box\scratchbox}% -% \dp\scratchbox\linetablerparameter{x\c!depth}% -% \ht\scratchbox\linetablerparameter{x\c!height}% -% \framed -% [\c!offset=\v!overlay, -% \c!frameoffset=.5\linewidth, -% \c!leftframe=\v!off,\c!rightframe=\v!off, -% \c!background=\v!color, -% \c!backgroundcolor=\linetablecparameter\c!backgroundcolor% -% ]{\box\scratchbox}% -% \else -% \backgroundline[\linetablecparameter\c!backgroundcolor]{\box\scratchbox}% -% \fi}% -% {\box\scratchbox}% -% \fi -% \egroup} - -\def\savelinetablepart - {\global\setbox\tablebox\linetablepart - \ifnum\linetablepart=\zerocount - \box\scratchbox % just storing - \else - \vbox - {\ifvoid\tablebox\linetablepart\else\unvbox\tablebox\linetablepart\fi - \doif{\linetablerparameter\c!background}\v!color - {\backgroundline[\linetablerparameter\c!backgroundcolor]}% - {\box\scratchbox}% is also arg to \backgroundline - \endgraf - \linetablerparameter\c!after}% - \fi} - -\def\flushlinetableparts - {\doglobal\increment\linetableline - \ifnum\linetableline<\noflinetablelines - % keep collecting - \else - \iflinetablepreroll - % forget about them - \else - \dorecurse\noflinetableparts - {\let\linetablepart\recurselevel - \dp\tablebox\linetablepart\strutdepth - % noindent en endgraf needed else whitespace mess-up! - \whitespace % here not after verticalstrut - \ifdim\topskipgap=\zeropoint\else - \verticalstrut\nobreak\kern-\struttotal\kern-\parskip\nobreak\nointerlineskip % fix topskip - \fi - \noindent\strut\hbox to \hsize{\box\tablebox\linetablepart\hss}\endgraf - \ifnum\linetablepart<\noflinetableparts\relax - \linetableparameter\c!inbetween - \fi}% - \ifnum\linetablerows<\noflinetablerows\relax - \linetableparameter\c!inbetween - \else - % after, later - \fi - \chardef\linetableheadstate\plusthree - \global\setbox\tablebox\zerocount\emptybox % here - \fi - % reset \linetablerow will be an option, currently - % starts at zero after split - \globallet\linetablerow\!!zerocount - \globallet\linetableline\!!zerocount - \global\chardef\linetablepage\zerocount - \global\linetablewidth\zeropoint - \setnoftableslines - \fi} - -\def\startlinetablepart - {\global\linetablesubcol\zerocount - \setbox\scratchbox\hbox\bgroup - \doconvertfont{\linetablerparameter\c!style}% - \startcolor[\linetablerparameter\c!color]% - \ignorespaces} - -\def\stoplinetablepart - {\ifnum\linetablepart>\zerocount - \unskip \unskip % remove last intercolumn skip (distance+fill) - \fi - \stopcolor - \egroup - \iflinetablepreroll \else - \ifcase\linetablepart - % we're collecting the repeater - \else - \scratchdimen\hsize \advance\scratchdimen-\wd\scratchbox\relax - \ifdim\scratchdimen>\linetableparameter\c!stretch\else - \setbox\scratchbox\hbox to \hsize{\unhbox\scratchbox}% - \fi - \fi - \fi} - -\def\checklinetablepart - {\global\advance\linetablewidth\wd\linetablecell - \global\advance\linetablecolumn\linetablestep - \global\advance\linetablesubcol\linetablestep - \relax - %\message{\the\linetablecolumn,\the\linetablesubcol}\wait - % from now on the column counter is already incremented - \ifcase\linetablesplitstate - \iflinetablepreroll \else - \box\linetablecell - % the columncounter is one ahead ! -% \hskip\linetablecparameter\c!afstand - \hskip\scratchskip - \fi - %%% - \donefalse - \ifcase\linetablerepeat\else - % van te voren berekenen - \scratchcounter\linetablecolumn\advance\scratchcounter-\plustwo - \ifnum\linetablerepeat=\scratchcounter - \donetrue % collecting repeater - \fi - \fi - %%%% - \ifdone - % collecting repeater - \else - \ifnum\linetablecolumn>\getvalue{\??le::\linetablepart}\relax - \donetrue - \fi - \fi - \ifdone - \stoplinetablepart - \iflinetablepreroll \else - \savelinetablepart - \fi - \ifcase\linetablepage \or - \global\chardef\linetablepage \plustwo - \else - \global\chardef\linetablepage \plusone - \fi - \doglobal\increment\linetablepart - \global\linetablewidth\wd\tablebox\zerocount - \startlinetablepart - \fi - \else - \donefalse - \!!doneafalse - \ifcase\linetablerepeat\else - % van te voren berekenen - \scratchcounter\linetablecolumn \advance\scratchcounter-\plustwo - \ifnum\linetablerepeat=\scratchcounter - \donetrue % collecting repeater - \fi - \fi - \ifdone - \!!doneatrue - % collecting repeater - \else\ifdim\linetablewidth>\hsize - \donetrue - \else -% \global\advance\linetablewidth\linetablecparameter\c!afstand\relax - \global\advance\linetablewidth\scratchskip - \ifdim\linetablewidth>\hsize % ? - \donetrue - \fi - \fi\fi - \ifdone - \stoplinetablepart - \savelinetablepart - \ifcase\linetablepage \or - \global\chardef\linetablepage \plustwo - \else - \global\chardef\linetablepage \plusone - \fi - \doglobal\increment\linetablepart - \ifnum\linetablepart>\noflinetableparts - \globallet\noflinetableparts\linetablepart - \initializetablebox\linetablepart - \fi - \global\linetablewidth\wd\linetablecell - \startlinetablepart - \if!!doneb \else \ifcase\linetablerepeat \else - % check for left/right page - \ifcase\linetablepage\donetrue\or\donetrue\or\donefalse\fi\ifdone - % insert repeater - \global\advance\linetablewidth\wd\tablebox\zerocount - \iflinetablepreroll\kern\wd\else\unhcopy\fi\tablebox\zerocount - \fi - \fi \fi - \fi - \iflinetablepreroll \else - \box\linetablecell - % the columncounter is one ahead ! -% \hskip\linetablecparameter\c!afstand -% \hskip\scratchskip -\dorecurse\linetablestep{\strut\hfil}% - \hskip\scratchskip - \fi - \fi} - -% \linetableparameter\c!var -> \@@levar (when no classes) - -\def\startlinetablerun % to do: quit when nested - {\bgroup - \inlinetabletrue - % autowidth - \doif{\linetableparameter\c!maxwidth}\v!fit - {\setuplinetable[\c!maxwidth=\zeropoint]}% - \processaction - [\linetableparameter\c!stretch] - [ \v!no=>{\setuplinetable[\c!stretch=\maxdimen]},% no stretch - \v!yes=>{\setuplinetable[\c!stretch=\zeropoint]}]% max stretch - \chardef\linetablerepeat\linetableparameter\c!nleft - \chardef\linetablesplitstate % = - \ifdim\linetableparameter\c!maxwidth>\zeropoint - \zerocount \else \plusone - \fi - % optional prevdepth correction - \iflinetablepreroll - \globallet\noflinetablerows\!!zerocount - \else - \linetableparameter\c!before - \fi - \globallet\linetablerows\!!zerocount - \globallet\noflinetablecolumns\!!zerocount - \globallet\noflinetableparts\!!zerocount - \!!counta\zerocount - \def\docommand##1% - {\doglobal\increment\noflinetableparts - \advance\!!counta##1% - \setxvalue{\??le::\noflinetableparts}{\the\!!counta}}% - \processcommacommand[\linetableparameter\c!n]\docommand - \initializetableboxes\noflinetableparts - \ifcase\linetablerepeat - \globallet\linetablepart\!!plusone - \else - \globallet\linetablepart\!!zerocount % repeater - \fi - \globallet\linetablestep\!!plusone - \globallet\linetableline\!!zerocount - \globallet\linetablerow \!!zerocount - \global\linetablecolumn \zerocount - \global\linetablesubcol \zerocount - \global\linetablewidth \zeropoint -\iflinetablepreroll \else \ifdim\pagetotal>\zeropoint - \verticalstrut\kern-\struttotal -\fi \fi - \setnoftableslines - \checklinetablepage - \let\BR\linetableBR - \let\ER\linetableER - \let\BH\linetableBR - \let\EH\linetableER - \let\BC\linetableBC - \let\EC\linetableEC - \let\NC\linetableNC - \let\NR\linetableNR - \flushlinetablehead} - -\def\stoplinetablerun - {\globallet\linetableline\!!maxcard - \chardef\linetableheadstate\zerocount % blocked - \flushlinetableparts - \iflinetablepreroll \else - \linetableparameter\c!after - \fi - \globallet\linetablepart \!!zerocount - \globallet\noflinetableparts\!!zerocount - \egroup} - -% \def\checklinecolumnwidth -% {\ifundefined{\??lew\number\linetablecolumn}% -% \donetrue -% \else\ifdim\getvalue{\??lew\number\linetablecolumn}<\wd\linetablecell -% \donetrue -% \else -% \donefalse -% \fi\fi -% \ifdone -% \setxvalue{\??lew\number\linetablecolumn}{\the\wd\linetablecell}% -% \fi} -% -% \def\checklinecolumnwidth -% {\ifcsname\??lew\number\linetablecolumn\endcsname -% \ifdim\csname\??lew\number\linetablecolumn\endcsname<\wd\linetablecell -% \donetrue -% \else -% \donefalse -% \fi -% \else -% \donetrue -% \fi -% \ifdone -% \setxvalue{\??lew\number\linetablecolumn}{\the\wd\linetablecell}% -% \fi} - -% \def\checklinecolumnwidth -% {\expandafter\xdef\csname\??lew\number\linetablecolumn\endcsname -% {\expandafter\ifx\csname\??lew\number\linetablecolumn\endcsname\relax -% \the\wd\linetablecell -% \else\ifdim\csname\??lew\number\linetablecolumn\endcsname<\wd\linetablecell -% \the\wd\linetablecell -% \else -% \csname\??lew\number\linetablecolumn\endcsname -% \fi\fi}} - -\def\checklinecolumndimension#1#2#3% - {\expandafter\xdef\csname#1\number#3\endcsname - {\expandafter\ifx\csname#1\number#3\endcsname\relax - \the#2\linetablecell - \else\ifdim\csname#1\number#3\endcsname<#2\linetablecell - \the#2\linetablecell - \else - \csname#1\number#3\endcsname - \fi\fi}} - -\def\checklinecolumnwidth {\checklinecolumndimension\??lew\wd\linetablecolumn} -\def\checklinecolumnheight{\checklinecolumndimension\??leh\ht\linetablerow} -\def\checklinecolumndepth {\checklinecolumndimension\??led\dp\linetablerow} - -\def\linetableBR - {\dosingleempty\dolinetableBR} - -\def\dolinetableBR[#1]% #1 not yet implemented - {\ifnum\linetableheadstate=1\else - \doglobal\increment\linetablerow - \doglobal\increment\linetablerows - \fi - \global\linetablecolumn\plusone - \global\linetablesubcol\plusone -% \linetableheight\linetablerparameter\c!height -% -% \ifx\linetableheight\empty -% % nothing -% \else\ifx\linetableheight\v!fit -% % keep it simple -% \else\ifx\linetableheight\v!line -% \chardef\linetablemode\plusone -% \else -% \!!heighta\linetableheight -% \advance\!!heighta-\strutdepth -% \fi\fi\fi -% - \linetableheight\zeropoint - \edef\!!stringa{\linetablerparameter\c!height}% - \ifx\!!stringa\empty - \chardef\linetablehmode\zerocount - \else\ifx\!!stringa\v!fit - \chardef\linetablehmode\plusone - \else\ifx\!!stringa\v!line - \chardef\linetablehmode\plustwo - \else - \linetableheight\!!stringa - \advance\linetableheight-\strutdepth - \fi\fi\fi -% - \startlinetablepart} - -\def\linetableBC - {\startlinetablecell} - -\def\linetableEC - {\stoplinetablecell - \iflinetablepreroll - \checklinecolumnwidth - \checklinecolumnheight - \checklinecolumndepth - \fi - \checklinetablepart} - -\def\linetableER - {% \stoplinetablecell - % no \box\linetablecell, i.e. dummy columnn, last \NC \NR - \stoplinetablepart - \savelinetablepart - \advance\linetablecolumn \minusone - \ifnum\linetablecolumn>\noflinetablecolumns - \xdef\noflinetablecolumns{\number\linetablecolumn}% - \fi - \flushlinetableparts - \global\linetablecolumn\zerocount - \global\linetablewidth \zeropoint - \ifcase\linetablerepeat - \globallet\linetablepart\!!plusone - \else - \globallet\linetablepart\!!zerocount % repeater - \fi - \checklinetablepage - \flushlinetablehead} - -\def\checklinetablepage - {\global\chardef\linetablepage\zerocount - \ifcase\linetablerepeat \else \ifcase\linetablepage - \doif{\linetableparameter\c!repeat}\v!no - {\global\chardef\linetablepage\doifoddpageelse\plusone\plustwo}% - \fi \fi} - -\def\flushlinetablehead - {\ifcase\linetableheadstate - % 0 blocked - \or - % 1 doing head - \or - % 2 head done - \or - % 3 trigger flush - \chardef\linetableheadstate\plusone - \the\@@linetablehead\relax - \chardef\linetableheadstate\plustwo - \fi} - -\def\linetableNC % first time special treatment - {\relax - \ifcase\linetablecolumn - \linetableBR - \else - \linetableEC - \fi - \linetableBC} % beware, this will result in BR BC EC BC NR - -\def\linetableNR - {\stoplinetablecell % dummy - \linetableER} - -\def\startlinetable - {\startlinetablerun} - -\def\stoplinetable - {\stoplinetablerun} - -\def\startlinetableanalysis - {\bgroup - \linetableprerolltrue - \trialtypesettingtrue - \startlinetablerun} - -\def\stoplinetableanalysis - {\stoplinetablerun - \egroup - \globallet\noflinetablerows\linetablerows - \dorecurse\noflinetablerows % global, from last run {\linetableparameter\c!n} - {%\writestatus{linetable}{\recurselevel->\getvalue{\??lew\recurselevel}}% - \setevalue{\??ler\recurselevel x\c!height}{\getvalue{\??leh\recurselevel}}% - \setevalue{\??ler\recurselevel x\c!depth }{\getvalue{\??led\recurselevel}}% - \letgvalue{\??leh\recurselevel}\!!zeropoint - \letgvalue{\??led\recurselevel}\!!zeropoint} - \dorecurse\noflinetablecolumns % global, from last run {\linetableparameter\c!n} - {%\writestatus{linetable}{\recurselevel->\getvalue{\??lew\recurselevel}}% - \setevalue{\??lec\recurselevel\c!width}{\getvalue{\??lew\recurselevel}}% - \letgvalue{\??lew\recurselevel}\!!zeropoint}} % init next table - -% todo: store in box instead of macro - -\newtoks \@@linetablehead - -\long\def\startlinetablehead#1\stoplinetablehead - {\ifinlinetable - \@@linetablehead\emptytoks - \fi - \chardef\linetableheadstate3 % full - \@@linetablehead{#1}% - \ifinlinetable - \flushlinetablehead - \fi} - -\def\linetableBH - {\ifx\EC\relax - % signal, grabbing lines - \else - \@@linetablehead\emptytoks - \fi - \pushmacro\BC - \pushmacro\EC - \def\BC##1\EC{\appendtoks##1\to\@@linetablehead}% - \let\EC\relax} % signal - -\def\linetableEH - {\popmacro\EC - \popmacro\BC - \@EA\startlinetablehead\the\@@linetablehead\stoplinetablehead} - -\let\startlinetablebody\donothing -\let\stoplinetablebody \donothing - -\def\processlinetablebuffer - {\dosingleempty\doprocesslinetablebuffer} - -\def\doprocesslinetablebuffer[#1]% - {\bgroup - \let\startlinetable\donothing - \let\stoplinetable \donothing - \startlinetableanalysis\getbuffer[#1]\stoplinetableanalysis - \startlinetablerun \getbuffer[#1]\stoplinetablerun - \egroup} - -\def\processlinetablefile#1% - {\bgroup - \let\startlinetable\donothing - \let\stoplinetable \donothing - \startlinetableanalysis\readfile{#1}\donothing\donothing\stoplinetableanalysis - \startlinetablerun \readfile{#1}\donothing\donothing\stoplinetablerun - \egroup} - -\protect \endinput - -\doifnotmode{demo}{\endinput} - -\setuplinetable[n=6,m={2,2,2},lines=25] % m ? - -\setuplinetable[c][1] [width=2cm,background=color,backgroundcolor=red] -\setuplinetable[c][4] [width=3cm,background=color,backgroundcolor=yellow] -\setuplinetable[c][6] [width=3cm,background=color,backgroundcolor=magenta] -\setuplinetable[r][odd] [background=color,backgroundcolor=gray] -\setuplinetable[r][even][background=color,backgroundcolor=green] - -\starttext - -\showframe \showstruts - -\setupcolors[state=start] - -\setuppagenumbering[alternative=doublesided]\page[left] - -\startlinetable -\NC aaa\crlf aaa \NC bb \NC c \NC ddddd \NC eeee \NC ff \NC \NR -\dorecurse{100}{\NC aaa \NC bb \NC c \NC ddddd \NC eeee \NC ff \NC \NR} -\stoplinetable - -\startlinetable -\NC[style=slanted,color=green,background=color,backgroundcolor=darkred,nx=2,uitlijnen=middle] xxx - \NC yy \NC ddddd \NC eeee \NC ff \NC \NR -\dorecurse{100}{\NC aaa \NC bb \NC c \NC ddddd \NC eeee \NC ff \NC \NR} -\stoplinetable - -% \startbuffer[lt] -% \NC aaa\crlf aaa \NC bb \NC c \NC ddddd \NC ee \NC ff \NC \NR -% \NC aaa\crlf aaa \NC b \NC cc \NC ddd \NC eeee \NC f \NC \NR -% \stopbuffer -% -% \processlinetablebuffer[lt] - -\stoptext 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.mkii b/tex/context/base/core-mis.mkii new file mode 100644 index 000000000..e860a537a --- /dev/null +++ b/tex/context/base/core-mis.mkii @@ -0,0 +1,2676 @@ +%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]% + {\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 [] + +% 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 +\newcounter\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 + \doglobal\increment\subsentencelevel + \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]% + \doglobal\decrement\subsentencelevel + \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 test 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\delimitedtextparameter#1% will be sped up + {\executeifdefined{\??ci\currentdelimitedtext:\csname\??ci\currentdelimitedtext\c!level\endcsname#1}% + {\executeifdefined{\??ci\currentdelimitedtext#1}% + {\executeifdefined{\??ci#1}\empty}}} + +\def\definedelimitedtext + {\dodoubleempty\dodefinedelimitedtext} + +\def\dodefinedelimitedtext[#1][#2]% + {\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\delimitedtextparameter\c!level\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}% + \doglobal\incrementvalue{\??ci\currentdelimitedtext\c!level}} + +\def\popdelimitedtext + {\doglobal\decrementvalue{\??ci\currentdelimitedtext\c!level}% + \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\!!tenthousand + \hskip\zeropoint % == \prewordbreak + \fi + \strut % new, needed below + \delimitedtextparameter#1% unhbox\scratchbox +% \penalty\!!tenthousand % 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\!!tenthousand + \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 + \hskip\hspaceamount\currentlanguage{interquotation}% + \else\ifdim\lastskip=\delimitedtextsignal + \unskip + \hskip\hspaceamount\currentlanguage{interquotation}% + \else + #2% + \fi\fi + \ifhmode % else funny pagebeaks + \penalty\!!tenthousand + \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 + +% Dit wordt: +% +% \doorverwijzen[naam][instellingen] enz. +% +% waarbij bijvoorbeeld publicatie is. Dit levert: +% +% \start +% \stop +% +% \beginvan +% \eindvan +% +% \publicatie +% +% \volledigelijstmetpublicaties +% +% eigenlijk kan ook door... zo worden uitgebreid! + +% 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={]}] + +% 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-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 test 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-mis.tex b/tex/context/base/core-mis.tex deleted file mode 100644 index de1da7597..000000000 --- a/tex/context/base/core-mis.tex +++ /dev/null @@ -1,2733 +0,0 @@ -%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 - -% 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. -% %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{\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\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]% - {\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 [] - -% 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 -\newcounter\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 - \doglobal\increment\subsentencelevel - \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]% - \doglobal\decrement\subsentencelevel - \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 test 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\delimitedtextparameter#1% will be sped up - {\executeifdefined{\??ci\currentdelimitedtext:\csname\??ci\currentdelimitedtext\c!level\endcsname#1}% - {\executeifdefined{\??ci\currentdelimitedtext#1}% - {\executeifdefined{\??ci#1}\empty}}} - -\def\definedelimitedtext - {\dodoubleempty\dodefinedelimitedtext} - -\def\dodefinedelimitedtext[#1][#2]% - {\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\delimitedtextparameter\c!level\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}% - \doglobal\incrementvalue{\??ci\currentdelimitedtext\c!level}} - -\def\popdelimitedtext - {\doglobal\decrementvalue{\??ci\currentdelimitedtext\c!level}% - \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\!!tenthousand - \hskip\zeropoint % == \prewordbreak - \fi - \strut % new, needed below - \delimitedtextparameter#1% unhbox\scratchbox -% \penalty\!!tenthousand % 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\!!tenthousand - \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 - \hskip\hspaceamount\currentlanguage{interquotation}% - \else\ifdim\lastskip=\delimitedtextsignal - \unskip - \hskip\hspaceamount\currentlanguage{interquotation}% - \else - #2% - \fi\fi - \ifhmode % else funny pagebeaks - \penalty\!!tenthousand - \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 - -% Dit wordt: -% -% \doorverwijzen[naam][instellingen] enz. -% -% waarbij bijvoorbeeld publicatie is. Dit levert: -% -% \start -% \stop -% -% \beginvan -% \eindvan -% -% \publicatie -% -% \volledigelijstmetpublicaties -% -% eigenlijk kan ook door... zo worden uitgebreid! - -% 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={]}] - -% 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 - -\startmessages dutch library: systems - 41: externe file -- in groep -- bestaat niet -\stopmessages - -\startmessages english library: systems - 41: external file -- in group -- does not exist -\stopmessages - -\startmessages german library: systems - 41: Externe Datei -- in Gruppe -- existiert nicht -\stopmessages - -\startmessages czech library: systems - 41: externi soubor -- ve skupine -- neexistuje -\stopmessages - -\startmessages italian library: systems - 41: il file esterno -- del gruppo -- non esiste -\stopmessages - -\startmessages norwegian library: systems - 41: ekstern fil -- i gruppe -- eksisterer ikke -\stopmessages - -\startmessages romanian library: systems - 41: fisierul extern -- din grupul -- nu exista -\stopmessages - -\startmessages french library: systems - 41: le fichier externe -- du groupe -- n'existe pas -\stopmessages - -\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: - -\newevery \everyinsidefloat \relax - -\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 - \calculatecos\@@rorotation\edef\cos{\calculatedcos\@@rorotation}% - \calculatesin\@@rorotation\edef\sin{\calculatedsin\@@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.mkii b/tex/context/base/core-nav.mkii new file mode 100644 index 000000000..f4594ab3b --- /dev/null +++ b/tex/context/base/core-nav.mkii @@ -0,0 +1,379 @@ +%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} + +%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-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-nav.tex b/tex/context/base/core-nav.tex deleted file mode 100644 index 045a05123..000000000 --- a/tex/context/base/core-nav.tex +++ /dev/null @@ -1,379 +0,0 @@ -%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} - -%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-new.tex b/tex/context/base/core-new.tex deleted file mode 100644 index e96039d10..000000000 --- a/tex/context/base/core-new.tex +++ /dev/null @@ -1,304 +0,0 @@ -%D \module -%D [ file=core-nav, -%D version=1995.01.01, -%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 / New Ones} - -\unprotect - -\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[% - {\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 [..] - -\def\dosetupsA #1{\cleanuplabel{#1}\processcommacommand[\cleanlabel]\dosetups} % {..} -\def\dosetupsB[#1]{\cleanuplabel{#1}\processcommacommand[\cleanlabel]\dosetups} % [..] -\def\dosetupsC[#1]{\cleanuplabel{#1}\dosetups\cleanlabel} % [..] - -% \def\dosetups#1% the grid option will be extended to other main modes -% {\executeifdefined{\??su\ifgridsnapping\v!grid\fi:#1} -% {\executeifdefined{\??su :#1}\gobbleoneargument}\empty} % takes one argument -% -% \def\setupwithargument#1% the grid option will be extended to other main modes -% {\executeifdefined{\??su:#1}\gobbleoneargument} - -% better: - -% \def\dosetups#1% the grid option will be extended to other main modes -% {\executeifdefined{\??su\ifgridsnapping\v!grid\fi:#1} -% {\executeifdefined{\??su :#1}\gobbleoneargument}\empty} % takes one argument -% -% \def\setupwithargument#1% the grid option will be extended to other main modes -% {\executeifdefined{\??su:#1}\gobbleoneargument} - -% faster: - -\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 - -% somehow fails ... -% -% \letvalue{\??su:..}\gobbleoneargument -% -% \def\dosetups#1% the grid option will be extended to other main modes -% {\csname \??su -% \ifcsname\??su\ifgridsnapping\v!grid\fi:#1\endcsname\v!grid:#1\else -% \ifcsname\??su :#1\endcsname :#1\else -% :..\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..\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\chardef\setupseolmode#1\doifnextcharelse[{\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% watch out: not \grabuntil -% {\dograbuntil#1{\endgroup\dodoglobal\long\setvalue{\??su#2:#3}}} % \doglobal -% -% better: - -% \long\def\dodostartsetups#1#2#3% watch out: not \grabuntil -% {\cleanuplabel{\??su#2:#3}\dograbuntil#1{\endgroup\dodoglobal\long\setvalue\cleanlabel}} % \doglobal - -% \long\def\dodostartsetups#1#2#3% -% {\cleanuplabel{\??su#2:#3}% -% \long\def\dododostartsetups##1#1{\endgroup\dodoglobal\long\setvalue\cleanlabel####1{##1}}\dododostartsetups} - -\long\def\dodostartsetups#1#2#3% - {\cleanuplabel{\??su#2:#3}% - \long\def\dododostartsetups##1#1% - {\endgroup - \dodoglobal % bah - \long\expandafter\setvalue\expandafter\cleanlabel\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 - {\ifundefined{\??su\ifgridsnapping\v!grid\fi:#1}% - \dodoglobal\letbeundefined{\??su:#1}% - \else - \dodoglobal\letbeundefined{\??su\ifgridsnapping\v!grid\fi:#1}% - \fi} - -% or -% -% \def\resetsetups[#1]% -% {\letbeundefined -% {\??su:% -% \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}}} - -\def\defineshortcut - {\dotripleargument\dodefineshortcut} - -\def\dodefineshortcut[#1][#2][#3]% - {\ifthirdargument - \ConvertConstantAfter\doifelse{#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} % - \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 \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 test -%D test test -%D test test -%D test test -%D zus<>zo zus<:>zo zus<::>zo -%D test test dat (ziezo) -%D test test dat (:ziezo) -%D test test dat (ziezo:) -%D test test dat (zi:ezo:) -%D well, 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 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\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 - -\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-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-ntb.tex b/tex/context/base/core-ntb.tex deleted file mode 100644 index 5bfba05ad..000000000 --- a/tex/context/base/core-ntb.tex +++ /dev/null @@ -1,1573 +0,0 @@ -%D \module -%D [ file=core-ntb, -%D version=2000.04.18, -%D title=\CONTEXT\ Core 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 Core 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 However, the next alternative also takes care of preceding -%D and following white space. - -% \def\bTBLCELL % why not \doinhibitblank -% {\inhibitblank\doconvertfont\tbltblstyle\empty\everypar{\delayedbegstrut}} - -% \def\eTBLCELL -% {\ifhmode -% \delayedendstrut -% \par % added 13/4/2006 -% \else -% \par -% \ifdim\prevdepth<\zeropoint % =-1000pt ? -% \vskip-\strutdp -% \else -% \removebottomthings -% \fi -% \fi} - -%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% -% {\setxvalue{\@@tblprefix#1:#2:l}{\TBLlevel}% -% \long\setvalue{\@@tblprefix#1:#2:t}% -% {\doifdefined{\@@tblprefix#1:#2:l} -% {\edef\TBLlevel{\getvalue{\@@tblprefix#1:#2:l}}}% -% #3}} - -\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} - -\presetlocalframed[\@@tbl\@@tbl] - -\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 - % 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 - \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} -\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 - \expanded{\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{\expanded{\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=]% - \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 foot, dus state var - -\long\def\bTABLEhead{\dosingleempty\doTABLEhead} -\long\def\bTABLEnext{\dosingleempty\doTABLEnext} -\long\def\bTABLEbody{\dosingleempty\doTABLEbody} -\long\def\bTABLEfoot{\dosingleempty\doTABLEfoot} - -\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 - \def\bTR{\dodoubleempty\parseTR}% - \def\bTD{\dodoubleempty\parseTD}% - \def\bTH{\dodoubleempty\parseTH}% - \def\bTN{\dodoubleempty\parseTN}} - -% permits \expanded{\bTD ... \eTD} - -\unexpanded\def\eTR{} -\unexpanded\def\eTD{} -\unexpanded\def\eTH{} -\unexpanded\def\eTN{} - -\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 - \expanded{\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 - \expanded{\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}} - -\setupTABLE - [\c!frameoffset=.5\linewidth, - \c!backgroundoffset=\v!frame, - \c!framecolor=\s!black, - \c!color=, - \c!style=, - \c!headstyle=\v!bold, - \c!headcolor=, - \c!strut=\v!yes, - \c!autostrut=\v!no, - \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!color=, - \c!style=, - \c!headstyle=, - \c!headcolor=, - \c!strut=\v!no, - \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/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<>} +%D \showsetup{<>} +%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<>} +%D \showsetup{<>} +%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<>} -%D \showsetup{<>} -%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.mkii b/tex/context/base/core-sec.mkii deleted file mode 100644 index 960de366f..000000000 --- a/tex/context/base/core-sec.mkii +++ /dev/null @@ -1,2620 +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 - -\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 - % but we don't want color to influence user commands - % todo: get the if-else out of it - \getvalue{\??ko#1\c!command} - {} % no number - {\dostartattributes{\??ko#1}\c!style\c!color\empty - \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 - \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 - % but we don't want color to influence user commands - \getvalue{\??ko#1\c!command}% - {\dostartattributes{\??ko#1}\c!style\c!color\empty - \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 - \dostopattributes} - {\dostartattributes{\??ko#1}\c!style\c!color\empty - \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 - \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!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.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 - -\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.tex b/tex/context/base/core-sec.tex new file mode 100644 index 000000000..6cc0fbbf9 --- /dev/null +++ b/tex/context/base/core-sec.tex @@ -0,0 +1,2572 @@ +%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} + +\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\pagebreakdisabledtrue + \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 +% \ifpagebreakdisabled +% \global\pagebreakdisabledfalse +% \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 + \ifpagebreakdisabled + \global\pagebreakdisabledfalse + \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 + +\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 + % but we don't want color to influence user commands + % todo: get the if-else out of it + \getvalue{\??ko#1\c!command} + {} % no number + {\dostartattributes{\??ko#1}\c!style\c!color\empty + \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 + \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 + % but we don't want color to influence user commands + \getvalue{\??ko#1\c!command}% + {\dostartattributes{\??ko#1}\c!style\c!color\empty + \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 + \dostopattributes} + {\dostartattributes{\??ko#1}\c!style\c!color\empty + \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 + \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 + \postponenotes + \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!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-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: -\ifx\pdfkeeplinedimen\undefined +% \def\doinhibitblank +% {\kern\noblanksignal} - \let\mksetupgridsnapping \relax - \let\mkenablegridsnapping \relax - \let\mkdisablegridsnapping\relax +% \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\mksetupgridsnapping - {\pdfeachlineheight \openstrutheight - \pdfeachlinedepth \openstrutdepth - \pdffirstlineheight \pdfeachlineheight - \pdflastlinedepth \pdfeachlinedepth} +\def\dotoggleindentation + {\gdef\checkindentation{\global\indentationfalse\notoggleindentation\donoindentation}} - \def\mkenablegridsnapping - {\pdfkeeplinedimen\maxdimen - \topskip\strutht - \offinterlineskip} +\def\notoggleindentation + {\gdef\checkindentation{\global\indentationtrue\dotoggleindentation}} - \def\mkdisablegridsnapping - {\pdfkeeplinedimen\zeropoint - % reset topskip - \oninterlineskip} +\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 \ 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\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\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} + +% 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\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\dosetstretch#1% to be interfaces - {\relax\ifdim#1>\zeropoint - \dosetattribute{kern-chars}{\number\dimexpr#1\relax}% +\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} -% experimental mirroring +\defineindentingmethod [\v!yes] {\parindent\ctxparindent\relax} % no \indent ! +\defineindentingmethod [\v!always] {\parindent\ctxparindent\relax} % no \indent ! -\defineattribute[mirror] +\defineindentingmethod [\v!never] {\parindent\zeropoint\relax % no \indent ! + \chardef\indentingtoggle\zerocount} -\def\setcharactermirroring - {\ctxlua{mirror.enabled=true}% - \gdef\setcharactermirroring[##1]{\dosetattribute{mirror}{\number##1}}% - \setcharactermirroring} +\defineindentingmethod [\v!odd] {\chardef\indentingtoggle\plusone} +\defineindentingmethod [\v!even] {\chardef\indentingtoggle\plustwo} -\def\resetcharactermirroring - {\doresetattribute{mirror}} +\defineindentingmethod [\v!normal] {\ifx\normalindentation\empty\else + \let\currentindentation\normalindentation + \simplesetupindenting + \fi} -\newtoks\everysetupdirections +\defineindentingmethod [\v!reset] {\indentfirstparagraphtrue + \parindent\zeropoint + \chardef\indentingtoggle\zerocount} -\def\setupdirections[#1]% there will be more like setting up directions themselves - {\getparameters[\??di][#1]% - \the\everysetupdirections} +\def\noindenting{\indenting[\v!no, \v!next ]} +\def\doindenting{\indenting[\v!yes,\v!first]} -\chardef\directionsbidimode=0 +%D This one sets up the local indentation behaviour (i.e. either or not +%D a next paragraph will be indented). -\letvalue{\??di:bidi:\v!off }\zerocount -\letvalue{\??di:bidi:\v!global}\plusone -\letvalue{\??di:bidi:\v!local }\plustwo -\letvalue{\??di:bidi:\v!on }\plustwo +\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} + +\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 - \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 + \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} -% bidi: local=obey grouping, global=ignore grouping (unicode has no grouping) +\def\autoindentation + {\global\chardef\recheckindentationmode\plusone} -\setupdirections % maybe start/stop - [bidi=\v!off] +%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 + -\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}} +%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}). -\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} +%D Hm ... todo: -% test at end of file +\sfcode`\)=0 +\sfcode`\'=0 +\sfcode`\]=0 -% for the moment: \setcharactermirroring[\plusone] +\def\setfrenchspacing#1% + {\sfcode`\.#1 \sfcode`\,#1\relax + \sfcode`\?#1 \sfcode`\!#1\relax + \sfcode`\:#1 \sfcode`\;#1\relax} -% experimental spacing +\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 \ 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} % -% test: oeps {\setcharacterspacing[frenchpunctuation]x: xx \bfd x: xx} oeps: test +% 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\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\setcharacterspacing - {\ctxlua{spacings.enabled=true}% - \gdef\setcharacterspacing[##1]{\dosetattribute{spacing}{\csname\??ch:##1\endcsname}}% - \setcharacterspacing} +\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\resetcharacterspacing - {\doresetattribute{spacing}} +\def\startunpacked + {\blank + \leavevmode + \bgroup} -\letvalue{\??ch:\s!reset}\minusone +\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. -% \setcharacterspacing[frenchpunctuation] -% «\type{bla}»\crlf « \type{bla}»\crlf -% «bla »\crlf « bla»\crlf « bla »\crlf -% bla: bla\crlf bla : bla +\def\toonregelcorrectie{\showbaselinecorrection} +\def\regelcorrectie {\baselinecorrection} -\definecharacterspacing [frenchpunctuation] % name may change / unit is em +% \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} -\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} -% more +\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 % -% {\setcharacterkerning[extrakerning]\input davis\relax} +% 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 -\defineattribute[kern] +\ifdefined\globalbodyfontsize\else + \newdimen\globalbodyfontsize + \globalbodyfontsize=12pt +\fi -\newcount \maxcharacterkerningid +\ifx\normalizedbodyfontsize\undefined + \def\normalizedbodyfontsize{12pt} +\fi -\def\definecharacterkerning - {\dosingleargument\dodefinecharacterkerning} +% 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\dodefinecharacterkerning[#1]% - {\ifcsname\??ck#1\endcsname \else - \global\advance\maxcharacterkerningid\plusone - \setxvalue{\??ck:#1}{\the\maxcharacterkerningid}% +\def\topskipcorrection + {\simpletopskipcorrection + \vskip-\struttotal + \verticalstrut} + +\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\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\dosetupcharacterkerning[#1][#2]% - {\ifcsname\??ck:#1\endcsname - \begingroup - \getparameters[\??ck][\c!factor=0,#2]% - \ctxlua{kerns.setspacing(\getvalue{\??ck:#1},\@@ckfactor)}% +\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\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 + +\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 + {\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: +% +% \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} + +\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 + \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=} + +\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\setcharacterkerning - {\ctxlua{kerns.enabled=true}% - \gdef\setcharacterkerning[##1]{\dosetattribute{kern}{\csname\??ck:##1\endcsname}}% - \setcharacterkerning} +\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 + +\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} -\letvalue{\??ck:\s!reset}\minusone +% 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:) -\definecharacterkerning[extrakerning] +\newif\ifpagechanged \let\lastchangedpage\empty -\setupcharacterkerning[extrakerning][\c!factor=.125] +\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} -% sorry, here: +\def\changedpagestate#1#2% + {\executeifdefined{#2:p:#1}{0}} -% test \WORD{test TEST \TeX} test -% test \word{test TEST \TeX} test -% test \Word{test TEST \TeX} test +\def\checkpagechange#1{\docheckpagestatechange{#1}\s!paragraph\nofraggedparagraphs} +\def\changedpage #1{\changedpagestate{#1}\s!paragraph} -\defineattribute[case] +% saved struts -\def\setcharactercasing - {\ctxlua{cases.enabled=true}% - \gdef\setcharactercasing[##1]{\dosetattribute{case}{\number##1}}% - \setcharactercasing} +\ifx\savedstrutbox\undefined \newbox\savedstrutbox \fi -\def\WORD {\groupedcommand{\setcharactercasing[\plusone ]}{}} -\def\word {\groupedcommand{\setcharactercasing[\plustwo ]}{}} -\def\Word {\groupedcommand{\setcharactercasing[\plusthree]}{}} -\def\Words{\groupedcommand{\setcharactercasing[\plusfour]}{}} +\def\savestrut {\setbox\savedstrutbox\copy\strutbox} +\def\savedstrut{\copy \savedstrutbox} -\let\WORDS\WORD -\let\words\word +\chardef\bottomraggedness=0 % 0=ragged 1=normal/align 2=baseline -% \definestartstop is not yet in available at core-spa time -% -% \startrandomized \input tufte \stoprandomized -% -% \definestartstop[randomized][\c!before=\dosetattribute{case}{8},\c!after=] +\def\bottomalignlimit{3\lineheight} -\def\randomizetext{\groupedcommand{\dosetattribute{case}{8}}{}} +\newif\ifn@rmalbottom +\newif\ifr@ggedbottom +\newif\ifb@selinebottom -% compound stuff (under construction) +\def\normalbottom + {% \topskip 10pt + \r@ggedbottomfalse} -\defineattribute[breakpoint] +\def\raggedbottom + {\chardef\bottomraggedness\zerocount + \n@rmalbottomfalse + \r@ggedbottomtrue + \b@selinebottomfalse + \settopskip} -\newbox\breakpointbox +\def\alignbottom + {\chardef\bottomraggedness\plusone + \n@rmalbottomtrue + \r@ggedbottomfalse + \b@selinebottomfalse + \settopskip} -\definesystemvariable {bp} % BreakPoint +\def\baselinebottom + {\chardef\bottomraggedness\plustwo + \n@rmalbottomfalse + \r@ggedbottomfalse + \b@selinebottomtrue + \settopskip} -\exhyphenchar=\minusone % we use a different order then base tex, so we really need this +\let\normalbottom=\alignbottom % downward compatible -\newcount \maxbreakpointsid +% new code, not in use yet -\def\definebreakpoints - {\dosingleargument\dodefinebreakpoints} +% 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 -\def\dodefinebreakpoints[#1]% - {\ifcsname\??bp:#1\endcsname \else - \global\advance\maxbreakpointsid\plusone - \setxvalue{\??bp:#1}{\the\maxbreakpointsid}% - \fi} +% 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) -\def\installbreakpoint - {\dotripleempty\doinstallbreakpoint} +% penalty: +% +% larger wins -% hm, we cannot prebuild lists, font dependent +% order: +% +% larger wins -\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 - \fi} +\registerctxluafile{core-spa}{1.001} -\def\setbreakpoints - {\ctxlua{breakpoints.enabled=true}% - \gdef\setbreakpoints[##1]{\dosetattribute{breakpoint}{\csname\??bp:##1\endcsname}}% - \setbreakpoints} +\definesystemattribute[kern-chars] +\definesystemattribute[skip-category] +\definesystemattribute[skip-penalty] +\definesystemattribute[skip-order] +\definesystemattribute[snap-category] +\definesystemattribute[display-math] -\letvalue{\??bp:\s!reset}\minusone +% \start \dosetstretch{.25em} \setuptolerance[tolerant,stretch] \input tufte \endgraf \stop +% \start \dosetstretch{.5em} effe flink doorfietsen \stop -\definebreakpoints[compound] +\def\dosetupgridsnapping % calls too often, only needed in gridsnapping + {\ctxlua{nodes.setsnapvalue(1,\number\openstrutheight,\number\openstrutdepth)}} -\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\doenablegridsnapping + {\dosetattribute{snap-category}{1}% + \topskip\strutht + \offinterlineskip} -% \setbreakpoints[compound] +\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 + +% 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} -\starttext +\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 \ 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 : @@ -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-tab.tex b/tex/context/base/core-tab.tex deleted file mode 100644 index 2e843eae8..000000000 --- a/tex/context/base/core-tab.tex +++ /dev/null @@ -1,2499 +0,0 @@ -%D \module -%D [ file=core-tab, -%D version=1997.10.10, -%D title=\CONTEXT\ Core Macros, -%D subtitle=\TABLE\ Embedding, -%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 / TaBlE Embedding} - -% By now it makes more sense to merge the patches into the original -% and clean that one up too. - -% Don't change the splitter: -% -% ... \NR -% \TABLEnoalign{\page}\TABLEhead -% \NC ... - -% e-tex: reverse rows or vadjust or ... in tables -% \ifalign -% \xhrule : calls for 'special' with width -% BUG: -% -% \starttable[|l|l|] -% \HL -% \RL\FR \VL Head 1 \VL Head 2 \VL\FR -% \RL\LR \VL Head A \VL Head B \VL\LR % niet grijs ?? -% \HL -% \VL 1 \VL 2 \VL\FR -% \VL a \VL b \VL\LR -% \HL -% \stoptable - -% melden als in kleur conflict, uitgestelde test op \SR\SR - -% verengelsen -% interface - -% footnotes flushen -% \......TABLE........ namen -% kolommen testen -% unbreakable kop definieren -% voetnoten -% meldingen -% als direct \use{max} dan fout -% \BREAKPOINT -% breedte lijn telt -% errors: ook gray in handle - -% \AR -> als in DL dan \DR - -% nieuw: -% -% \NL / \NL[blanko] is skip, nog default? -% geen \HL in a row -% \HL[n] -% \VL[n] + remembers -% c{colorspec} key -% \HC[color][width] -% \VC[color] -% meldingen row, column, use, advise -% \AR: UITSTELLEN / EXPERIMENTEEL - -% WAARDELOZE ERROR HANDLER -% THIS RENEWED MODULE WORKS OK BUT STILL LOOKS BAD - -%D We felt no need to write our own table building macros, -%D simply because Michael Wichura made a terrific one. This -%D package is quite complete and well documented. In \CONTEXT\ -%D we provide a shell for consistent spacing as well as color -%D support. Implementing these features without adapting the -%D original macros is not trivial. One easilly gets conflicts -%D with \type{\omit}, \type{\span} and \type{\noalign}, which -%D means that we end up postponing and overloading macros, -%D mostly global. Now, let's start with loading the main -%D macros: - -\doifundefined{BeginTable}{\doinputonce{table.tex}} - -\unprotect - -%D \macros -%D {inintable, ifsplittables} -%D -%D First we declare some variables. These show a bit what we -%D are dealing with. First we introdoce some booleans that -%D enable us, inside as well as outside this module, to -%D determine in what mode we are. - -\newif\ifintable -\newif\ifsplittables - -%D \macros -%D {tracetablestrue} -%D -%D When I documented this module, I felt the need for tracing -%D options. After implementing this feature, I also added -%D warnings, error recovery and automatic spacing. - -\newif\iftracetables - -%D We show this feature in an eample that also shows some of -%D the basic table typesetting commands. -%D -%D \startbuffer -%D \starttable[|||] -%D \HL -%D \VL first \VL second \VL\AR -%D \HL -%D \VL alfa \VL 1 \VL\AR -%D \VL beta \VL 2 \VL\AR -%D \VL gamma \VL 3 \VL\AR -%D \HL -%D \stoptable -%D \stopbuffer -%D -%D \startcombination -%D {\tracetablesfalse\getbuffer} {\type{\tracetablesfalse}} -%D {\tracetablestrue\getbuffer} {\type{\tracetablestrue}} -%D \stopcombination -%D -%D This table is specified as: -%D -%D \typebuffer -%D -%D This examples shows about the minimum of commands needed to -%D typeset such a table. In this table, the \type {\AR} is -%D automatically translated into the more primitive (but more -%D verbose) commands \type {\SR}, \type {\FR}, \type {\MR} and -%D \type {\LR} commands. -%D -%D \startbuffer -%D \starttables[|||] -%D \HL -%D \VL first \VL second \VL\AR -%D \HL -%D \VL alfa \VL 1 \VL\AR -%D \VL beta \VL 2 \VL\AR -%D \VL gamma \VL 3 \VL\AR -%D \HL -%D \stoptable -%D \stopbuffer -%D -%D When we use the split table feature, we get a bit more -%D information. -%D -%D {\tracetablesfalse\getbuffer} -%D -%D Sometimes in tables information shows up that is not typed -%D in by the user. These messages give a cue in what aspect a -%D table definition is wrong. -%D -%D \startbuffer -%D \starttable[||||] -%D \HL -%D \VL first second \VL third \VL\AR -%D \HL -%D \VL alfa \VL 1 \VL a \VL\AR -%D \VL beta \VL 2 \VL b \VL -%D \VL gamma \VL \THREE{3} c \VL\AR -%D \HL -%D \stoptable -%D \stopbuffer -%D -%D \typebuffer -%D -%D Those terrible table has three errors, which all show up in -%D typeset messages. Errors cannot always recovered 100\% and -%D therefore can result in two or more succesive messages, like -%D in the last row. -%D -%D \getbuffer - -%D Bringing color into tables is complicated by the mere fact -%D that color is not part of \TEX. The main complication is -%D that we don't know in advance how wide a column will be. I -%D implemented color support in tables in the early 90's -%D because I needed it for some articles on color. I have to -%D admit that I seldom use the mechanism. -%D -%D Most color support in \CONTEXT\ makes use of colored rules. -%D At first sight, one is tempted to implement colors in tables -%D in a similar way, but as said, we don't know the dimensions -%D in advance. It turns out however that we don't have to, -%D simply because alignments take care of stretching rules to -%D the appropritate dimensions. This means that we can provide -%D backgrounds by coloring rules with the height of a row, -%D skipping upwards and finally drawing the content, like in: -%D -%D \gdef\ShowExample -%D {\startfiguretext -%D {none} -%D {\getbuffer} -%D \typebuffer -%D \stopfiguretext} -%D -%D \startbuffer -%D \starttable[|c|c|] -%D \HL -%D \BL[2] \SR -%D \VL test \VL test \VL\SR -%D \HL -%D \VL test \VL test \VL\FR -%D \VL test \VL test \VL\MR -%D \VL test \VL test \VL\LR -%D \HL -%D \stoptable -%D \stopbuffer -%D -%D \ShowExample -%D -%D Just to be complete we show how the other columns can be -%D given a background. Later we will provide more details over -%D the commands used. -%D -%D \startbuffer -%D \starttable[|c|c|c|] -%D \HL -%D \BL[3] \SR -%D \VL test \VL test \VL test \VL\SR -%D \HL -%D \stoptable -%D \stopbuffer -%D -%D \ShowExample -%D -%D \startbuffer -%D \starttable[|c|c|c|] -%D \HL -%D \BC \BL[2] \SR -%D \VL test \VL test \VL test \VL\SR -%D \HL -%D \stoptable -%D \stopbuffer -%D -%D \ShowExample -%D -%D \startbuffer -%D \starttable[|c|c|c|] -%D \HL -%D \BC \BC \BL \SR -%D \VL test \VL test \VL test \VL\SR -%D \HL -%D \stoptable -%D \stopbuffer -%D -%D \ShowExample -%D -%D \startbuffer -%D \starttable[|c|c|c|] -%D \HL -%D \BC \BL \SR -%D \VL test \VL test \VL test \VL\SR -%D \HL -%D \stoptable -%D \stopbuffer -%D -%D \ShowExample -%D -%D \startbuffer -%D \starttable[|c|c|c|] -%D \BL \BL \SR -%D \HL -%D \VL test \VL test \VL test \VL\SR -%D \HL -%D \stoptable -%D \stopbuffer -%D -%D \ShowExample - -%D In these examples we can clearly see that for being a real -%D background, the color or gray specification has to precede -%D the content. Just to keep things simple, we can recall this -%D specification later on: -%D -%D \startbuffer -%D \starttable[|c|c|c|] -%D \BC \BL \SR -%D \HL -%D \VL test \VL test \VL test \VL\SR -%D \HL -%D \BR\FR -%D \VL test \VL test \VL test \VL\FR -%D \BR\MR -%D \VL test \VL test \VL test \VL\MR -%D \BR\LR -%D \VL test \VL test \VL test \VL\LR -%D \HL -%D \stoptable -%D \stopbuffer -%D -%D \ShowExample -%D -%D Close study learns that we can put the specification -%D before or after the \type{\HL}, whatever suits best. Keeping -%D track of these specifications is taken care of by the next -%D variables: - -\newif \ifTABLEgrayline % executing gray line -\newif \ifTABLEgraydone % gray line executed -\newtoks \TABLEgraytoks % gray line specification - -\newif\ifTABLEinbreak - -%D Nog vervangen: - -\def\c!Table{Table} -\def\m!TABLE{TABLE} - -%D We already saw that the table macros report errors and -%D provide automatic spacing. These features can only be -%D implemented by keeping track of the state, often the last -%D command on a row. - -\chardef\TABLEunknown = 0 - -\chardef\TABLEseparaterow = 1 -\chardef\TABLEfirstrow = 2 -\chardef\TABLEmidrow = 3 -\chardef\TABLElastrow = 4 -\chardef\TABLErule = 5 -\chardef\TABLEskip = 6 -\chardef\TABLEautorow = 7 - -\chardef\TABLEforcefirstrow = 1 -\chardef\TABLEforcelastrow = 2 - -\chardef\TABLEmissingrow = 1 -\chardef\TABLEmissingcolumn = 2 -\chardef\TABLEspanoverflow = 3 -\chardef\TABLEdivisionoverflow = 4 - -%D We store these states using efficient \type {\chardef}'s. -%D Like most variables, these are global ones. When needed, -%D especially when we flush the backgrounds, we can temporary -%D disable the assignment. - -\newif\ifsetTABLEaction - -\def\setTABLEaction#1% - {\ifsetTABLEaction\global\chardef\TABLEaction#1\fi} - -\def\setTABLEforce#1% - {\ifsetTABLEaction\global\chardef\TABLEforce#1\fi} - -\def\setTABLEerror#1% - {\global\chardef\TABLEerror#1} - -%D Before we come to using these variables, we redefine and/or -%D adapt some \TABLE\ macros. Within \TABLE's the \type{|} and -%D \type{"} have special meanings in templates and are active -%D during. Their meaning can therefore conflict with those -%D elsewhere defined. To be compatible with traditional \TABLE\ -%D as well as \CONTEXT's \type{||} and the active \type{"} -%D extensions for my german friends, we do some catcode magic. - -\newif\ifForgetTableBarAndQuote \ForgetTableBarAndQuotetrue - -% \bgroup - -% \catcode`\|=\@@active -% \catcode`\"=\@@active -% -% \gdef\pushouterbarandquote -% {\ifForgetTableBarAndQuote -% \ifnum\catcode`\|=\@@active \let\outertablebar |\else\let\outertablebar \relax\fi -% \ifnum\catcode`\"=\@@active \let\outertablequote"\else\let\outertablequote\relax\fi -% \let|\letterbar -% \let"\letterdoublequote -% \fi} -% -% \gdef\popouterbarandquote -% {\ifForgetTableBarAndQuote -% \ifx\outertablebar \relax\else\let|\outertablebar \fi -% \ifx\outertablequote\relax\else\let"\outertablequote\fi -% \else -% \redefinetablebarandquote -% \fi} -% -% \egroup -% -% \def\ObeyTableBarAndQuote -% {\ForgetTableBarAndQuotefalse -% \ifintable -% \redefinetablebarandquote -% \fi} - -\let\ActivateBarAndQuote \relax -\let\ObeyTableBarAndQuote\relax -\let\pushouterbarandquote\relax -\let\popouterbarandquote \relax - -%D \macros -%D {ObeyTableBarAndQuote} -%D -%D As said, the \type{|} and \type{"} active characters are -%D often used for other purposes. By default, the outside -%D meanings are therefore preserved and available inside -%D tables. If for some reason one wants to use the \TABLE\ -%D primitives, one can say: -%D -%D \starttyping -%D \ObeyTableBarAndQuote -%D \stoptyping -%D -%D To keep things verbose, as well as to show what \TABLE\ -%D commands we affect, we show some meanings. - -\def\normalTABLEshortrule {\!ttShortHrule} % \- -\def\normalTABLElongrule {\!ttLongHrule} % \= -\def\normalTABLEfullrule {\!ttFullHrule} % \_ -\def\normalTABLEendofrow {\!ttEndOfRow} % \\ -\def\normalTABLEsimplebar {\unskip\!ttRightGlue&&} % | -\def\normalTABLEcomplexbar {\unskip\!ttRightGlue&\omit\!ttAlternateVrule} % \| -\def\normalTABLEquote {\unskip\!ttRightGlue&\omit&} % " -\def\normalTABLElineformat {\normalTABLEendofrow+} -\def\normalTABLElineending {\normalTABLEendofrow0 } -\def\normalTABLEsinglerule {&\normalTABLElongrule&} -\def\normalTABLEmultirule#1{&\use{#1}\normalTABLElongrule&} - -%D The next hack is dedicated to Tobias, who found out that -%D paragraph entries don't break well. - -\def\TABLEhack{\hskip\zeropoint} - -%D The first attemp to solve this problem was: -%D -%D \starttyping -%D \def\normalTABLEquote% -%D {\unskip\TABLEhack\!ttRightGlue&\omit&\TABLEhack} -%D \stoptyping -%D -%D But, as usual, this interfered with \type {\omit}. -%D -%D The next attempt is redefining some core \TABLE\ macro:. -%D This works ok, but breaks for instance the~\type{b} -%D key handling. -%D -%D \starttyping -%D \def\!tfAdjoinPriorColumn% -%D {\ifnum\!taColumnNumber=0 -%D \!taPreamble=\!taRuleColumnTemplate -%D ... -%D \if!taOnceOnlyTabskip -%D \!thToksEdef\!taDataColumnTemplate= -%D {\TABLEhack####\TABLEhack\tabskip\the\!taLastRegularTabskip} -%D \else -%D \!taDataColumnTemplate{\TABLEhack##\TABLEhack}% -%D \fi -%D ... -%D \ReadFormatKeys} -%D \stoptyping - -% \newdimen\TABLEparheight - -\def\BeginTableParBox#1% - {\setbox\scratchbox\vtop\bgroup % \setbox added - \hsize#1\relax - \normalbaselines - \let~\!ttTie - \let\-\!ttDH - \blank[\v!disable]% % added - \the\EveryTableParBox} - -\def\EndTableParBox - {\removelastskip % itemize or so - \endgraf - \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 - \vtop to \noflines\lineheight{\box\scratchbox}% - \fi % esp between rows - \else % of paragraphs - \egroup - \fi -% \getboxheight\scratchdimen\of\box\scratchbox\relax% compensate for -% \ifdim\scratchdimen>\TABLEparheight % funny depth of -% \global\TABLEparheight\scratchdimen % multi-line box -% \fi % i.e. vtop - \box\scratchbox} - -% We also need to patch away the interfering math switch: - -% \mathpunctuationtrue - -% test, test -% \starttable[|c|] -% \NC1,,10\NC\AR -% \stoptable -% test, test - -\def\!ttBeginTableA[#1]{% - \if #1u% % "unboxed" table - \ifmmode - \def\!ttEndTable{% % user had better be in display math mode - \relax}% % and have only one table at the outer level - \else % user had better be in vertical mode - \bgroup - \def\!ttEndTable{% - \egroup}% - \fi - \else - %\hbox\bgroup $ - %\def\!ttEndTable{% - % \egroup % for the \vtop, \vbox, or \vcenter, yet to come - % $% for math mode - % \egroup}% for the \hbox - %\if #1t% - % \vtop - %\else - % \if #1b% - % \vbox - % \else - % \vcenter % math mode was essential for this - % \fi - %\fi - % - \hbox\bgroup - \def\!ttEndTable{\egroup\egroup}% - \if#1t% - \vtop - \else\if#1b% - \vbox - \else - \def\!ttEndTable{\egroup$\egroup}% - %$\vcenter - \scratchtoks\everymath\everymath\emptytoks$\everymath\scratchtoks\vcenter - \fi\fi - % - \bgroup % for the \vtop, \vbox, or \vcenter - \fi - \advance\!taRecursionLevel 1 % RecursionLevel governs initialization - \let\!ttRightGlue=\relax % This may be changed by \JustCenter, etc - \everycr\emptytoks % ={} - \ifnum \!taRecursionLevel=1 - \!ttInitializeTable - \fi} - -%D The next redefinition is more robust than the original: - -\def\SetTableToWidth#1% - {\doifelsenothing{#1}{\!taTableSpread\emptytoks}{\!taTableSpread{to #1}}} - -% (*) Try this one with \type {direction} and {girection}; -% the \PPCHTEX\ manual is a nice testcase. -% -% \startoverlay -% {\starttable[ | l w(2cm) | w(8cm) | ] -% \HL -% \VL direction \VL \showbaselines \dorecurse{3}{direction }\VL \FR -% \VL direction \VL \showbaselines \dorecurse{3}{direction }\VL \MR -% \VL direction \VL \showbaselines \dorecurse{3}{direction }\VL \LR -% \HL -% \stoptable} -% {\starttable[ | l w(2cm) | p(8cm) | ] -% \HL -% \VL direction \VL \showbaselines \dorecurse{3}{direction }\VL \FR -% \VL direction \VL \showbaselines \dorecurse{3}{direction }\VL \MR -% \VL direction \VL \showbaselines \dorecurse{3}{direction }\VL \LR -% \HL -% \stoptable} -% \stopoverlay -% \vskip2cm -% \starttable[ | l w(2cm) | p(8cm) | ] -% \HL -% \VL direction \VL \showbaselines \dorecurse{3}{direction }\VL \FR -% \VL direction \VL \showbaselines \dorecurse{8}{direction }\VL \LR -% \HL -% \stoptable -% \vskip2cm -% \starttable[ | l w(2cm) | p(8cm) | ] -% \HL -% \VL direction \VL \showbaselines \dorecurse{8}{direction }\VL \FR -% \VL direction \VL \showbaselines \dorecurse{8}{direction }\VL \LR -% \HL -% \stoptable - -%D To give an impression of what the (well documented) source -%D of \TABLE\ looks like, we first implement an alternative for -%D the numeric keys. The quantity keys (\type{q} and \type{Q}) -%D support the more european way of writing numbers: -%D -%D \startnarrower -%D 100.000.000,00 instead of 100,000,000.00 -%D \stopnarrower -%D -%D The next table shows how to use these keys. We use braces -%D instead of brackets because we need brackets to specify the -%D format. -%D -%D \startbuffer -%D \starttable{|q[00,000]|Q[00,00]|} -%D \HL -%D \VL -1,2 \VL 12,35 \VL\FR -%D \VL 11,203 \VL 2,4 \VL\LR -%D \HL -%D \stoptable -%D \stopbuffer -%D -%D \ShowExample -%D -%D Although a more efficient implementation is possible |<|we -%D can for instance share common macros|>| we just adapt a copy -%D of the numeric ones. To permit double loading of this -%D module, we check for the existence of one of the macros. - -\letvalue{!tk<\string q>}=\undefined -\letvalue{!tk<\string Q>}=\undefined - -%D We just copy the original {\em comments}. -%D -%D \em Key \type{q}: quantity item, non||math mode. - -\NewFormatKey q% - {\letempty\!tqStyle - \futurelet\!tnext\!tqTestForBracket} - -%D \em Key \type{Q}: quantity item, math mode. - -\NewFormatKey Q% - {\def\!tqStyle{$}% - \futurelet\!tnext\!tqTestForBracket} - -%D \em Note: the space between a quantity entry and the -%D following \type{|}, \type{"}, or \type{\|} is mandatory. -%D empty quantity entries are not allowed: use \type{{}} or -%D \type{\omit} instead. -%D -%D \em Test for bracket: invoked by the keys \type{q} and -%D \type{Q}. - -\def\!tqTestForBracket - {\ifx[\!tnext - \!thx\!tqGetArgument - \else - \!thx\!tqGetCode - \fi} - -%D \em Get code: e.g. \type{4}, or \type{4,0}, \type{0,4}, or -%D \type{10,2}. - -\def\!tqGetCode#1 % note the blank - {\!tqConvertCode #1,,!} - -%D \em Convert code: e.g. converts above to \type{[0000]}, -%D \type{[0000,]}, \type{[,0000]}, \type{[0000000000,00]}. - -\def\!tqConvertCode #1,#2,#3!% - {\begingroup - \aftergroup\edef - \aftergroup\!ttemp - \aftergroup{% - \aftergroup[% - \!taCountA #1 - \!thLoop - \ifnum \!taCountA>\zerocount - \advance\!taCountA \minusone - \aftergroup0 - \repeat - \def\!ttemp{#3}% - \ifx\!ttemp\empty - \else - \aftergroup, - \!taCountA #2 - \!thLoop - \ifnum\!taCountA>\zerocount - \advance\!taCountA \minusone - \aftergroup0 - \repeat - \fi - \aftergroup]\aftergroup}% - \endgroup\relax - \!thx\!tqGetArgument\!ttemp} - -%D \em Get argument: -%D -%D \starttyping -%D -%D \stoptyping - -\def\!tqGetArgument[#1]% - {\!tqMakeQuantityTemplate\!tqStyle#1,,!} - -%D \em Make quantity template. - -\def\!tqMakeQuantityTemplate#1#2,#3,#4!% #1= or $ - {\def\!ttemp{#4}% - \ifx\!ttemp\empty - \!taDimenC\zeropoint - \else - \setbox0\hbox{\m@th #1,#3#1}% - \!taDimenC\wd0 - \fi - \setbox0\hbox{\m@th #1#2#1}% - \!thToksEdef\!taDataColumnTemplate - ={\noexpand\!tqSetQuantityItem{\the\wd0 }{\the\!taDimenC}{#1}% - \the\!taDataColumnTemplate}% - \ReadFormatKeys} - -%D \em Set numeric item. - -\def\!tqSetQuantityItem #1#2#3#4 % - {\!tqSetQuantityItemA{#1}{#2}{#3}#4,,!} - -\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}} - -%D Here ends the Q||extension. Did you watch the clever use -%D of aftergroup in \type{\!tqConvertCode}. - -% %D We also (have to) define a key for \type{\cap}: -% -% \letvalue{!tk<\string K>}=\undefined -% -% \NewFormatKey K% -% {\ReadFormatKeys b\smallcapped} - -%D A few pages back we saw backgrounds, further on we will see -%D colored rules, and here we provide a means to color the -%D entries in a column. (We can of course always use the normal -%D color commands for individual entries.) We could not use the -%D lowercase~\type{c}, because that one is used to force {\em -%D centering}. -%D -%D \startbuffer -%D \starttable[|C{red}|C{green}|C{blue}|] -%D \VL R(ed) \VL G(reen) \VL B(lue) \VL\SR -%D \stoptable -%D \stopbuffer -%D -%D \ShowExample - -\letvalue{!tk<\string C>}=\undefined - -\NewFormatKey C#1% - {\ReadFormatKeys b{\localstartcolor[#1]} a{\localstopcolor}} - -%D So now we have three new keys: -%D -%D \starttable[|||] -%D \HL -%D \NC \bf key \NC \bf meaning \NC\AR -%D \HL -%D \NC Q[x,y] \NC math mode formatted numbers \NC\AR -%D \NC q[x,y] \NC text mode formatted numbers \NC\AR -%D \NC C{identifier} \NC column entry color \NC\AR -%D \HL -%D \stoptable - -%D To be compatible with the tabulate environment, we also -%D support the \type {l}, \type {c} and \type {r} keys for -%D paragraph entries. - -\letvalue{!tk<\string l>}=\undefined -\letvalue{!tk<\string c>}=\undefined -\letvalue{!tk<\string r>}=\undefined -\letvalue{!tk<\string x>}=\undefined % not that needed - -\NewFormatKey c% - {\prependtoks\raggedcenter\to\!taDataColumnTemplate - \ReadFormatKeys \LeftGlue\hfil \RightGlue\hfil} - -\NewFormatKey l% - {\prependtoks\raggedright\to\!taDataColumnTemplate - \ReadFormatKeys \LeftGlue\empty \RightGlue\hfil} - -\NewFormatKey r% - {\prependtoks\raggedleft\to\!taDataColumnTemplate - \ReadFormatKeys \LeftGlue\hfil \RightGlue\empty} - -\NewFormatKey x% - {\prependtoks\notragged\to\!taDataColumnTemplate - \ReadFormatKeys \LeftGlue\hfil \RightGlue\empty} - -\appendtoks \TABLEparalignment \to \EveryTableParBox - -\def\!tfReFormat#1% - {\the \!taLeftGlue - \vbox{\forgetall\ialign{\span\the\!taDataColumnTemplate\cr#1\cr}}% - \the \!taRightGlue - \kern\zeropoint} % prevents \unskip / really needed - -%D Later on, we're going to implement multiple page table -%D support, therefore the next \TABLE\ macro needs to be -%D slightly adapted, i.c. the penalty is removed. We also -%D add basic color support. - -\def\!ttFullHruleA - {\!ttGetHalfRuleThickness - \startglobalTABLEcolor % added - \hrule\!thHeight\dimen0\!thDepth\dimen0 - \stopglobalTABLEcolor % added - %\penalty0 % removed - \egroup} - -%D We'll see that when we want to give a vertical rule a color, -%D we have to set and reset states. After heavy testing it -%D proved most useful to extend a \TABLE\ primitive with some -%D hooks. One thing to keep in mind is that \type{&} keeps -%D assignments local. Again, we add basic color support. - -\let\TABLEbeforebar\empty -\let\TABLEafterbar \empty - -\def\@VLn{1} -\def\@VLd{.125em} - -\def\do!ttInsertVrule % will be merged in 2005 - {\vrule \!thWidth - \ifnum\!tgCode=\plusone - \ifx\!tgValue\empty - \LineThicknessFactor - \else - \!tgValue - \fi - \LineThicknessUnit - \else - \!tgValue - \fi - \hskip\@VLd} - -\def\!ttInsertVrule - {\hfil - \TABLEbeforebar % added - \startglobalTABLEcolor % added - % we could do without this speedup, some day merge 'm - \ifcase\@VLn\or - \do!ttInsertVrule - \unskip - \else - \dorecurse\@VLn\do!ttInsertVrule - \gdef\@VLn{1}% - \unskip - \fi - \stopglobalTABLEcolor % added - \TABLEafterbar % added - \hfil - &} - -%D The next two macros are only adapted to basis rule -%D color support. - -\def\!tfSetVrule - {\!thToksEdef\!taRuleColumnTemplate= - {\noexpand\hfil - \noexpand\startglobalTABLEcolor % added - \noexpand\vrule - \noexpand\!thWidth - \ifnum\!tgCode=\plusone - \ifx\!tgValue\empty - \the\LineThicknessFactor - \else - \!tgValue - \fi - \!taLTU - \else - \!tgValue - \fi - ####% - \noexpand\hfil - \noexpand\stopglobalTABLEcolor % added - \the\!taRuleColumnTemplate}% - \!tfAdjoinPriorColumn} - -\def\!ttShortHruleA - {\!ttGetHalfRuleThickness - \startglobalTABLEcolor % added - \leaders\hrule\!thHeight\dimen0\!thDepth\dimen0\hfill - \stopglobalTABLEcolor % added - \null - \ignorespaces} - -%D We already showed the next one, but here we slightly adapt -%D the macro by adding an \type{\expandafter}. The space after -%D \type{#1} is crucial! - -\def\normalTABLEcomplexbar#1% - {\unskip\!ttRightGlue&\omit\expandafter\!ttAlternateVrule#1 } - -%D To get rid of interfering \type{\omit}'s when we are -%D checking the number of columns and reporting problems. The -%D extensions concern the second level check, the first -%D subbranch and advancing the column. - -\ifx\mscount\undefined \newcount\mscount \fi - -\def\!ttuse#1% - {\ifnum#1>\plusone - \omit - \global\TABLEdivisionfalse - \scratchcounter\currentTABLEcolumn % added - \advance\scratchcounter #1% % added - \advance\scratchcounter \minusone % added - \ifnum\scratchcounter>\maxTABLEcolumn % added - \def\next % added - {\setTABLEerror\TABLEspanoverflow % added - \handleTABLEerror}% % added - \else % added - \def\next % added - {\global\advance\currentTABLEcolumn #1% % added - \global\advance\currentTABLEcolumn \minusone % added - \mscount#1% \mscount is in Plain - \advance\mscount \minusone - \advance\mscount \mscount - \!thLoop - \ifnum\mscount>\plusone - \sp@n % from Plain (\span\omit \advance\mscount\m@ne) - \repeat - \span}% - \fi % added - \else % added - \def\next % conflicts with possible next \omit % added - {\global\advance\currentTABLEcolumn \plusone}% % added - \fi - \next} % added - -% \starttable[|c|c|c|c|] -% \HL -% \VL {test} \VL \TWO{} \VL test \VL\FR -% \DL \DC \DL\DR -% \VL {test} \VL \TWO{} \VL test \VL\LR -% \HL -% \stoptable - -%D All commands that are executed between rows are to be put in -%D \type {\noalign}. We can however not verify if we (that is -%D \TABLE) does or did not enter this mode. A moderate dirty -%D but useful trick is using our own alternative:\footnote{Once -%D one has entered the stage of redefining \TEX\ primitives, -%D such hacks become a second nature. However, redefining \type -%D {\omit} and \type{\span} is not that easy.} - -\def\TABLEnoalign - {\noalign\bgroup\let\noalign\relax\let\next=} - -%D \macros -%D {starttable} -%D -%D The rest of this module is not easy to comprehend, mainly -%D because we have to take care of: -%D -%D \startitemize[packed] -%D \item \type{\startitemize[template]} -%D \item \type{\startitemize{template}} -%D \item \type{\startitemize[predefined]} -%D \stopitemize -%D -%D as well as: -%D -%D \startitemize[continue] -%D \item restart after table break -%D \stopitemize -%D -%D The official specification of the start command is: -%D -%D \showsetup{starttable} - -\newconditional\tablerepeathead -\newconditional\tablerepeattail - -\def\starttable - {\bgroup - \doif\@@tisplit\v!auto - {\ifinsidesplitfloat\let\@@tisplit\v!yes\fi}% - \doifinsetelse\@@tisplit{\v!yes,\v!repeat} - {\def\stoptable{\stoptables\egroup}% - \starttables} - {\doifelsenothing\@@tiframe - {\ifinsidefloat\else\startbaselinecorrection\fi} - {\startframedcontent[\@@tiframe]}% - \postponefootnotes - \firststagestartTABLE}} - -\def\stoptable - {\chuckTABLEautorow % before the tail, else noalign problem - \insertTABLEtail - \TABLEnoalign{\globalletempty\@@TABLEhead}% - \TABLEnoalign{\globalletempty\@@TABLEtail}% - \finishTABLE - \doifelsenothing\@@tiframe - {\ifinsidefloat\else - \stopbaselinecorrection - \goodbreak % compensates all the nobreaks - \fi} - \stopframedcontent - \egroup} - -%D Before we can grab the argument, we have to make sure that -%D the \CATCODES\ are set. The first stage takes care of that. - -\def\firststagestartTABLE - {\bgroup % kan-ie weg? - \global\intabletrue - \pushouterbarandquote - %catcode`\|=\@@other - \complexorsimple\secondstagestartTABLE} - -\def\simplesecondstagestartTABLE#1% - {\complexsecondstagestartTABLE[{#1}]} - -%D \macros -%D {definetabletemplate} -%D -%D The complex (and main) start macro first takes care of the -%D predefined case. Such a predefined setup looks like: -%D -%D \starttyping -%D \definetabletemplate[test][|||] -%D -%D \starttable[test] -%D \VL test \VL test \VL\AR -%D \VL test \VL test \VL\AR -%D \VL test \VL test \VL\AR -%D \stoptable -%D \stoptyping -%D -%D The implementation of the definition macro is not that -%D complicated: - -\def\definetabletemplate % to be redone - {\bgroup - \catcode`\|=\@@other - \doquadrupleempty\dodefinetabletemplate} - -\def\dodefinetabletemplate[#1][#2][#3][#4]% - {\ifsecondargument - \setgvalue{\c!Table#1}{\douseTABLEtemplate{#2}{#3}{#4}}% - \fi - \egroup} - -\def\douseTABLEtemplate#1#2#3% - {\gdef\TABLEhead{\getvalue{@@TABLEhead#2}}% - \gdef\TABLEtail{\getvalue{@@TABLEtail#3}}% - \complexsecondstagestartTABLE[#1]} - -%D The optional third and fourth arguments define which table -%D head and tail to use. -%D -%D \starttyping -%D \definetabletemplate[test][|||][before][after] -%D \stoptyping -%D -%D This also means that one can define table heads and tails -%D by name! -%D -%D \starttyping -%D \starttablehead[before] -%D \HL \VL first \VL second \VL \SR \HL -%D \stoptablehead -%D \stoptyping -%D -%D Templates defined this way get protected names, that cannot -%D conflict with existing commands. -%D -%D \showsetup{definetabletemplate} -%D -%D The second half of the next macro prepares table -%D splitting. - -\def\insertTABLEhead - {\TABLEnoalign{\global\settrue \preventTABLEbreak \global\setfalse\someTABLEhead}% - \TABLEhead - \TABLEnoalign{\global\setfalse\preventTABLEbreak}} - -\def\insertTABLEtail - {\TABLEnoalign{\global\settrue \preventTABLEbreak \global\setfalse\someTABLEtail}% - \TABLEtail - \TABLEnoalign{\global\setfalse\preventTABLEbreak}} - -% \def\dorestartTABLE#1% -% {\gdef\restartTABLE{#1}% -% \restartTABLE -% \insertTABLEhead -% \ifsplittables \ifconditional \tablerepeattail -% \TABLEnoalign{\goodbreak}% -% \insertTABLEtail -% \TABLEnoalign{\goodbreak}% -% \fi \fi} - -\def\verysimpleTableHL - {\TABLEnoalign{\expandafter\normalTABLEfullrule\@@tiHLheight}} - -\def\dorestartTABLE#1% - {\gdef\restartTABLE{#1}% - \restartTABLE - \TABLEnoalign{\globalpushmacro\simpleTableHL\global\let\simpleTableHL\verysimpleTableHL}% - \insertTABLEhead - \ifsplittables \ifconditional \tablerepeattail - \TABLEnoalign{\goodbreak}% - \insertTABLEtail - \TABLEnoalign{\goodbreak}% - \fi \fi - \TABLEnoalign{\globalpopmacro\simpleTableHL}} - -\bgroup \catcode`|=\@@other \catcode`"=\@@other - -\gdef\complexsecondstagestartTABLE#1[#2]% brr nested mess - {\bgroup - \@@useotherbar - \@@useotherquote - \global\setfalse\someTABLEhead - \global\setfalse\someTABLEtail - \expanded{\doifinstringelse{|}{#2}} - {\xdef\restartTABLE{\noexpand\dorestartTABLE{\noexpand\thirdstagestartTABLE{#2}}}} - {\doifdefinedelse{\c!Table#2} - {\gdef\restartTABLE{\getvalue{\c!Table#2}}} - {\gdef\restartTABLE{\dorestartTABLE{\getvalue{#2}}}}}% - \egroup - \restartTABLE} - -\egroup - -%D The third stage involves a lot of (re)sets, which we will -%D explain later. - -%D The next definition is convenient and more in tune with -%D \CONTEXT. - -\let \everytable \EveryTable - -%D We immediately use this register: - -\appendtoks - \fixedspaces - \let\_\normalunderscore -\to \everytable - -%D Now we can start the table. - -\def\thirdstagestartTABLE#1% - {\global\setTABLEactiontrue - \setTABLEaction\TABLEunknown - \setTABLEforce\TABLEunknown - \setTABLEerror\TABLEunknown - \global\TABLEgraylinefalse - \global\TABLEgraydonefalse - \globalletempty\TABLEgrayline - \globalletempty\nextTABLEgrayline - \globalletempty\TABLEgraylineerror - \globalletempty\TABLEgraylinestatus - \resetVLvalues - \appendtoks\popouterbarandquote\to\EveryTable - \appendtoks\localTABLEsetup\to\EveryTable - \BeginTable[\ifsplittables u\else b\fi]% - \defineTABLEunits - \defineTABLEsteps - \defineTABLErules - \defineTABLEdivisions - \defineTABLEshorthands - \defineTABLEbackgrounds - \defineTABLEendings - \forgetall % added - \doifsomething{#1} - {\def\TABLEformat{#1}% - \getTABLEnofcolumns\TABLEformat - % more modern is to use catcode tables - \expandafter\BeginFormat\TABLEformat\EndFormat}} - -\def\finishTABLE - {\chuckTABLEautorow - \unskip\crcr - \EndTable - \global\intablefalse - \egroup} - -%D \macros -%D {starttables} -%D -%D Split tables are specified using the plural form of the -%D start and stop commands. -%D -%D \showsetup{starttables} -%D -%D For example: -%D -%D \starttyping -%D \starttables[|||] -%D \HL -%D \VL element \VL atom weight \VL\AR -%D \HL -%D \VL ....... \VL ........... \VL\AR -%D \VL ....... \VL ........... \VL\AR -%D \HL -%D \stoptables -%D \stoptyping - -\newbox\tablecontentbox - -\def\starttables - {\bgroup - \splittablestrue - \doifelse\@@tisplit\v!repeat - {\settrue \tablerepeathead\settrue \tablerepeattail} - {\setfalse\tablerepeathead\setfalse\tablerepeattail}% - \flushnotes - \setbox\tablecontentbox\vbox\bgroup - \forgetall - \global\TABLEinbreakfalse - \firststagestartTABLE} - -% \def\stoptables -% {\ifconditional\tablerepeattail\else\insertTABLEtail\fi -% \finishTABLE -% \egroup -% \dosplittablebox\tablecontentbox -% \flushnotes -% \egroup} - -\def\stoptables - {\chuckTABLEautorow % AM: before the tail, else noalign problem - \ifconditional\tablerepeattail\else\insertTABLEtail\fi - \finishTABLE - \egroup - \dosplittablebox\tablecontentbox - \flushnotes - \egroup} - -\newdimen\TABLEcaptionheight % obsolete - -\def\dosplittablebox#1% - {\resettsplit - \def\tsplitminimumfreelines{2}% - \def\tsplitminimumfreespace{\TABLEcaptionheight}% - \setbox\tsplitcontent\box#1% - \ifconditional\tablerepeathead \ifconditional\someTABLEhead - \setbox\tsplithead\vsplit\tsplitcontent to \lineheight - \setbox\tsplithead\vbox{\unvbox\tsplithead}% - \fi \fi - \ifconditional\tablerepeattail \ifconditional\someTABLEtail - \setbox\tsplittail\vsplit\tsplitcontent to \lineheight - \setbox\tsplittail\vbox{\unvbox\tsplittail}% - \fi \fi - \ifinsidefloat\else - \def\tsplitbeforeresult{\startbaselinecorrection}% - \def\tsplitafterresult {\stopbaselinecorrection}% - \fi - \handletsplit} - -%D When the table in the previous example is split across -%D pages, only the first gets a head. We could have said -%D something like: -%D -%D \starttyping -%D \starttablekop -%D \HL -%D \VL element \VL atom weight \VL\AR -%D \HL -%D \stoptablekop -%D -%D \starttablestaart -%D \HL -%D \stoptablestaart -%D -%D \starttables[|||] -%D \VL ....... \VL ........... \VL\AR -%D \VL ....... \VL ........... \VL\AR -%D \stoptables -%D \stoptyping -%D -%D This time each split table gets a head line and ends with -%D a rule. Keep in mind that such heads also apply to the -%D unbroken ones and should be defined local (grouped) if -%D needed. The rather complicated definition below is due to -%D the fact that the stopcondition is interface language -%D dependant. - -\let\@@TABLEhead\empty \def\TABLEhead{\@@TABLEhead} -\let\@@TABLEtail\empty \def\TABLEtail{\@@TABLEtail} - -\letvalue{\e!start\v!tablehead}=\undefined -\letvalue{\e!stop \v!tablehead}=\undefined -\letvalue{\e!start\v!tabletail}=\undefined -\letvalue{\e!stop \v!tabletail}=\undefined - -\expanded - {\def\csname\e!start\v!tablehead\endcsname##1\csname\e!stop\v!tablehead\endcsname% - {\noexpand\setTABLEhead##1\noexpand\end}} - -\expanded - {\def\csname\e!start\v!tabletail\endcsname##1\csname\e!stop\v!tabletail\endcsname% - {\noexpand\setTABLEtail##1\noexpand\end}} - -%D The second argument is a dummy one, by scanning for it, we -%D get rid of interfering spaces. - -\def\setTABLEhead{\dodoubleempty\dosetTABLEhead} -\def\setTABLEtail{\dodoubleempty\dosetTABLEtail} - -\newconditional\preventTABLEbreak -\newconditional\someTABLEhead - -\def\dosetTABLEhead[#1][#2]#3\end{\setvalue{@@TABLEhead#1}{\TABLEnoalign{\global\settrue\someTABLEhead}#3}} -\def\dosetTABLEtail[#1][#2]#3\end{\setvalue{@@TABLEtail#1}{\TABLEnoalign{\global\settrue\someTABLEtail}#3}} - -%D Redudant \type{\HL}'s are removed automatically, so -%D mid||lines can be used without problems. - -%D We need an alternative for the normal complex or simple -%D commands, because assignments in these system commands -%D conflict with \type{\noalign}. This alternative is about -%D as efficient as possible. - -\def\complexorsimpleTable#1#2% - {\csname\if[\noexpand#2\s!complex\else\s!simple\fi\c!Table#1\endcsname#2} - -%D The next one is used in \type{\VL} cum suis and honours -%D the next grouping. - -\def\docomplexorsimpleTable#1#2% - {\ifx\next\bgroup\@EA#2\else\@EA\dodocomplexorsimpleTable\@EA#1\@EA#2\fi} - -\def\dodocomplexorsimpleTable#1#2#3% - {\if[\noexpand#3\@EA#1\else\@EA#2\fi#3} - -%D The order of the next macros is more or less random. First -%D we implement error recovery. Errors are reported to the -%D screen and log file as well as visualized in the table in -%D teletype. - -\def\handleTABLEerror - {\ifTABLEgrayline \else - \ifnum\TABLEerror=\TABLEunknown \else - \setTABLEaction\TABLEunknown - \globalletempty\checkTABLEautorow - \globalletempty\chuckTABLEautorow - \fi - \ifcase\TABLEerror - % no error - \or - % \TABLEmissingrow - \tttf [missing row]% - \writestatus\m!TABLE{missing row}% - \SR - \or - % \TABLEmissingcolumn - \fillTABLEcolumns - \tttf [missing column]% - \writestatus\m!TABLE{missing column}% - \SR - \or - % \TABLEspanoverflow - \fillTABLEcolumns - \tttf [columnspan too large]% - \writestatus\m!TABLE{columnspan too large}% - \SR - \or - % \TABLEdivisionoverflow - \fillTABLEcolumns - \tttf [division line too long]% - \writestatus\m!TABLE{division line too long}% - \SR - \fi - \fi - \ifnum\TABLEerror=\TABLEunknown \else - \finishTABLErow - \fi} - -\def\finishTABLErow - {\crcr - \TABLEnoalign - {\nobreak - \setTABLEaction\TABLEunknown - \setTABLEerror\TABLEunknown - \globalletempty\checkTABLEautorow - \globalletempty\chuckTABLEautorow - \global\currentTABLEcolumn\zerocount}} - -\def\fillTABLEcolumns - {\ifnum\currentTABLEcolumn>\maxTABLEcolumn \else - \global\advance\currentTABLEcolumn \plusone - \normalTABLEquote - \expandafter\fillTABLEcolumns - \fi} - -%D Next we enter the more complicated area of column and row -%D switching. I won't go into much detail from now on, but just -%D mention the general principles. -%D -%D \startitemize[3*ruim] -%D \sym{\type{\SR}} end a separate row (between rules) -%D \sym{\type{\FR}} end a first row (after a rule) -%D \sym{\type{\MR}} end a mid row (between text lines) -%D \sym{\type{\LR}} end a last row (before a rule) -%D \stopitemize -%D -%D and best of all: -%D -%D \startitemize[continue] -%D \sym{\type{\AR}} end a row with automatic spacing -%D \stopitemize -%D -%D As far as possible, we report confusing situations. In -%D most cases one can use \type{\AR}, which transfigurates -%D itself into one of the other types. -%D -%D \starttyping -%D \starttable[||] -%D \HL -%D \VL a separate row \VL\SR -%D \HL -%D \VL a first row \VL\FR -%D \VL a mid row \VL\MR -%D \VL a last row \VL\LR -%D \HL -%D \stoptable -%D \stoptyping -%D -%D In this example we could have used \type{\AR} without -%D problems. -%D -%D Color or gray scale backgrounds precede the content. They -%D are passed over horizontal (division) lines when needed. -%D Errors in the color template are traced elsewhere. Here we -%D only check for inconsistent spacing. Due to the way \TEX\ -%D handles alignments, we cannot automate spacing for colored -%D rows and columns. - -\chardef\TABLErowzero=0 - -\def\checkTABLErow#1% pure for message purposes - {\unskip % added - \ifTABLEgraydone - \defconvertedargument\asciia{#1}% - \defconvertedcommand \asciib\TABLEendBCL - \ifx\asciia\asciib \else - \writestatus\m!TABLE{confusing \asciia\space and \asciib}% - \gdef\TABLEgraylineerror% - {\globalletempty\TABLEgraylineerror - [\asciia\unskip<->\asciib\unskip]}% - \fi - \global\TABLEgraydonefalse - \fi} - -\def\defineTABLEendings - {\let\SR\TableSR - \let\FR\TableFR - \let\MR\TableMR - \let\LR\TableLR - \let\AR\TableAR} - -\def\TableSR - {\ifTABLEgrayline \else - \ifnum\TABLEaction=\TABLEfirstrow - \writestatus\m!TABLE{change \string\SR\space into \string\MR/\string\LR}% - \else\ifnum\TABLEaction=\TABLEmidrow - \writestatus\m!TABLE{change \string\SR\space into \string\MR/\string\LR}% - \else\ifnum\TABLEaction=\TABLEmidrow - \writestatus\m!TABLE{change \string\SR\space into \string\MR/\string\LR}% - \fi\fi\fi - \fi - \checkTABLErow\SR - \endTABLErow\TABLEseparaterow\TABLErowfactor\TABLErowfactor} - -\def\TableFR - {\ifTABLEgrayline \else - \ifnum\TABLEaction=\TABLEmidrow - \writestatus\m!TABLE{change \string\FR\space into \string\MR/\string\LR}% - \else\ifnum\TABLEaction=\TABLElastrow - \writestatus\m!TABLE{change \string\FR\space into \string\MR/\string\LR}% - \fi\fi - \fi - \checkTABLErow\FR - \endTABLErow\TABLEfirstrow\TABLErowfactor\TABLErowzero} - -\def\TableMR - {\ifTABLEgrayline \else - \ifnum\TABLEaction=\TABLErule - \writestatus\m!TABLE{change \string\MR\space into \string\FR/\string\SR}% - \else\ifnum\TABLEaction=\TABLElastrow - \writestatus\m!TABLE{change \string\MR\space into \string\FR}% - \fi\fi - \fi - \checkTABLErow\MR - \endTABLErow\TABLEmidrow00} - -\def\TableLR - {\ifTABLEgrayline \else - \ifnum\TABLEaction=\TABLErule - \writestatus\m!TABLE{change \string\LR\space into \string\FR/\string\SR}% - \fi - \fi - \checkTABLErow\LR - \endTABLErow\TABLElastrow\TABLErowzero\TABLErowfactor} - -%D \macros -%D {ifcheckTABLEcolums} -%D -%D -%D The next macros handle the actual row ending. This macro -%D also take care of space corrections due to table splitting -%D when \type{\MR} and collegues are used. When tracing is -%D enabled, the corrections as well as the values used to -%D determine the available space are shown (in color). By default -%D checking is off. - -\newif\ifcheckTABLEcolumns - -\let\beforeTABLEline\empty -\let\afterTABLEline \empty - -\def\doendTABLErow#1#2#3% - {\handleTABLEbreak#2#3% - \beforeTABLEline - \ifcase#1\relax - % unknown - \or - \endofTABLEline[blue][\SR->\SR]\TABLErowfactor\TABLErowfactor - \or - \endofTABLEline[red][\FR->\FR]\TABLErowfactor\TABLErowzero - \or - \ifnum\TABLEforce=\TABLEforcelastrow - \endofTABLEline[red][\MR->\LR]\TABLErowzero\TABLErowfactor - \else\ifnum\TABLEforce=\TABLEforcefirstrow - \endofTABLEline[red][\MR->\FR]\TABLErowfactor\TABLErowzero - \else - \endofTABLEline[green][\MR->\MR]\TABLErowzero\TABLErowzero - \fi\fi - \or - \endofTABLEline[red][\LR->\LR]\TABLErowzero\TABLErowfactor - \fi - \TABLEnoalign - {\setTABLEforce\TABLEunknown - \global\currentTABLEcolumn\zerocount}% - \afterTABLEline} - -\def\endTABLErow#1#2#3% - {\setTABLEaction#1% - \ifTABLEgrayline - \finishTABLErow - \else - \ifnum\currentTABLEcolumn>\maxTABLEcolumn - \doendTABLErow{#1}{#2}{#3}% - \else\ifcheckTABLEcolumns - \setTABLEerror\TABLEmissingcolumn - \handleTABLEerror - \else - \doendTABLErow{#1}{#2}{#3}% - \fi\fi - \fi} - -%D Handling \type{\AR} is postponed till the next row. The -%D check takes care of the first and mid rows, the chuck macro -%D |<|how about that name|>| handles the last row. - -\def\TableAR - {\ifTABLEgraydone - \globalletempty\checkTABLEautorow - \globalletempty\chuckTABLEautorow - \global\TABLEgraydonefalse - \TABLEendBCL - \else - \globallet\checkTABLEautorow\docheckTABLEautorow - \globallet\chuckTABLEautorow\dochuckTABLEautorow - \fi} - -\let\checkTABLEautorow\empty -\let\chuckTABLEautorow\empty - -\def\docheckTABLEautorow - {\globallet\checkTABLEautorow\empty - \ifnum\TABLEaction=\TABLErule \FR - \else\ifnum\TABLEaction=\TABLEunknown \FR - \else \MR - \fi\fi} - -\def\dochuckTABLEautorow - {\globalletempty\checkTABLEautorow - \globalletempty\chuckTABLEautorow - \ifnum\TABLEaction=\TABLErule \SR - \else\ifnum\TABLEaction=\TABLEunknown \SR - \else \LR - \fi\fi} - -%D When a table is split, we also add a tail and when present -%D we repeat the table head. - -\def\handleTABLEbreak#1#2% - {\globalletempty\beforeTABLEline - \gdef\afterTABLEline{\TABLEnoalign{\ifconditional\preventTABLEbreak\nobreak\else\goodbreak\fi}}} - -%D When tables are split, the spacing before and after a -%D horizontal rule is corrected according to what we expect. - -\def\endofTABLEline[#1][#2->#3]#4#5% - {\ifx#2#3\else - \writestatus\m!TABLE{\string#2\space changed into \string#3}% - \fi - \iftracetables - \bgroup - \tttf\space - \ifnum\TABLEerror=\TABLEunknown - \ifx#2#3\else\string#2->\fi - \else - ->% - \fi - \color[#1]{\string#3}% - \ifx\TABLEgraylineerror\empty - \space\TABLEgraylinestatus - \else - \space\TABLEgraylineerror - \fi - \egroup - \else\ifx\TABLEgraylineerror\empty \else - % \bgroup - % \tttf\space\TABLEgraylineerror - % \egroup - \fi\fi - \globalletempty\TABLEgraylinestatus - \globalletempty\TABLEgraylineerror - \expandafter\normalTABLElineformat#4#5\crcr % \crcr nodig ? - \TABLEnoalign{\nobreak\global\setTABLEactiontrue}} - -%D In order to prevent (as good as possible) alignment overflow -%D and therefore \TEX\ error messages, we check the maximum -%D number of columns. We keep track of the current column and -%D maximum column by means of two \COUNTERS. Keep in mind that -%D the number of \type{|}'s and \type{\VL}'s or alike is always -%D one more than the number of columns. - -\newcount\currentTABLEcolumn -\newcount\maxTABLEcolumn - -%D While defining this macro we change the \CATCODE\ of -%D \type{|}. When counting the bars, we use a non active -%D representation of the bar, simply because we cannot be sure -%D if the bar is active or not.\footnote{Normally it is, but -%D \TABLE\ changes the catcode when needed.} - -\bgroup - \catcode`\|=\@@other \gdef\@@otherbar {|} - \catcode`\"=\@@other \gdef\@@otherquote {"} - \catcode`\|=\@@active \gdef\@@useotherbar {\let|\@@otherbar} - \catcode`\"=\@@active \gdef\@@useotherquote{\let"\@@otherquote} -\egroup - -\bgroup \catcode`\|=\@@other - -\gdef\getTABLEnofcolumns#1% - {\bgroup - \cleanupfeatures % needed ! - \@@useotherbar - \@@useotherquote - \expanded{\defconvertedargument\noexpand\ascii{#1}}% - \@EA\doglobal\@EA\counttoken\@EA|\@EA\in\ascii\to\maxTABLEcolumn - \global\advance\maxTABLEcolumn \minusone - % in case of & counting, divide by 2 - \egroup} - -\egroup - -\def\!ttDoHalign - {\baselineskip \zeropoint - \lineskiplimit\zeropoint - \lineskip \zeropoint - \tabskip \zeropoint - % does not work in normal tex - % \expanded{\getTABLEnofcolumns{\the\!taPreamble}}% added - \halign \the\!taTableSpread \bgroup - \span\the\!taPreamble - \ifx \!tfRowOfWidths \empty \else \!tfRowOfWidths \cr \fi} - -%D \startitemize[3*ruim] -%D \sym{\type{\VL}} a vertical line -%D \sym{\type{\VC}} a vertical colored line -%D \sym{\type{\HL}} a horizontal line -%D \sym{\type{\HC}} a horizontal colored line -%D \stopitemize - -% \def\defineTABLErules -% {\let\VL\TableVL -% \let\VC\TableVC -% \let\HL\TableHL -% \let\HC\TableHC} - -\def\defineTABLErules - {\let\VL\TableVL - \let\VC\TableVC - \let\HL\TableHL - \let\HC\TableHC - \let\VS\TableVS - \let\VD\TableVD - \let\VT\TableVT - \let\VN\TableVN} - -\def\TableVL - {\checkTABLEautorow - \nextTABLEgrayline - \ifnum\currentTABLEcolumn>\maxTABLEcolumn - \setTABLEerror\TABLEmissingrow - \handleTABLEerror - \else - \global\advance\currentTABLEcolumn \plusone - \expandafter\doTableVL - \fi} - -\def\doTableVL - {\futurelet\next\dodoTableVL} - -\def\dodoTableVL - {\docomplexorsimpleTable\complexTableVL\simpleTableVL} - -\def\complexTableVL[#1]% - {\scratchcounter=0#1% - \multiply\scratchcounter \@@tiVLwidth - \setxvalue{wVL\the\currentTABLEcolumn}{\the\scratchcounter}% - \simpleTableVL} - -\def\simpleTableVL - {\doifundefined{wVL\the\currentTABLEcolumn}% - {\setgvalue{wVL\the\currentTABLEcolumn}{\@@tiVLwidth}}% - \gdef\TABLEbeforebar - {\getvalue{bVL\the\currentTABLEcolumn}% - \letgvalueempty{bVL\the\currentTABLEcolumn}}% - \gdef\TABLEafterbar - {\getvalue{eVL\the\currentTABLEcolumn}% - \letgvalueempty{eVL\the\currentTABLEcolumn}}% - \edef\@@tiVLwidth{\getvalue{wVL\the\currentTABLEcolumn}}% - \expanded{\normalTABLEcomplexbar\@@tiVLwidth\space}}% \relax breaks \use - -% \starttable[|||] -% \HL -% \VL test \VS test \VL \FR -% \VL test \VD test \VL \MR -% \VL test \VT test \VL \LR -% \HL -% \stoptable - -\def\TableVS {\VN1} -\def\TableVD {\VN2} -\def\TableVT {\VN3} -\def\TableVN#1{\gdef\@VLn{#1}\VL} - -\def\resetVLvalues - {\dostepwiserecurse\zerocount\maxTABLEcolumn\plusone - {\setgvalue{wVL\recurselevel}{\@@tiVLwidth}% - \letgvalueempty{bVL\recurselevel}% - \letgvalueempty{eVL\recurselevel}}% - \global\currentTABLEcolumn\zerocount} - -\def\TableVC - {\checkTABLEautorow - \nextTABLEgrayline - \ifnum\currentTABLEcolumn>\maxTABLEcolumn - \setTABLEerror\TABLEmissingrow - \handleTABLEerror - \else - \global\advance\currentTABLEcolumn \plusone - \expandafter\doTableVC - \fi} - -\def\doTableVC - {\futurelet\next\dodoTableVC} - -\def\dodoTableVC - {\docomplexorsimpleTable\complexTableVC\simpleTableVC} - -\def\complexTableVC[#1]% - {\global\setvalue{bVC\the\currentTABLEcolumn}{\localstartcolor[#1]}% - \global\setvalue{eVC\the\currentTABLEcolumn}{\localstopcolor}% - \simpleTableVC} - -\def\simpleTableVC - {\global\setvalue{bVL\the\currentTABLEcolumn}% - {\getvalue{bVC\the\currentTABLEcolumn}}% - \global\setvalue{eVL\the\currentTABLEcolumn}% - {\getvalue{eVC\the\currentTABLEcolumn}}% - \doTableVL} - -\def\TableHL - {\ifnum\currentTABLEcolumn>\maxTABLEcolumn - \chuckTABLEautorow - \else\ifnum\currentTABLEcolumn=\zerocount - %\chuckTABLEautorow - \TABLEnoalign - {\globalletempty\checkTABLEautorow - \globalletempty\chuckTABLEautorow}% - \else - \setTABLEerror\TABLEmissingcolumn - \handleTABLEerror - \fi\fi - \complexorsimpleTable{HL}} - -\def\complexTableHL[#1]% - {\TABLEnoalign - {\scratchcounter0#1% - \multiply\scratchcounter \@@tiHLheight - \edef\@@tiHLheight{\the\scratchcounter}% - \simpleTableHL}} - -\def\simpleTableHL - {\TABLEnoalign - {\nobreak - \ifnum\TABLEaction=\TABLErule - \writestatus\m!TABLE{skipping \string\HL}% \statusmessage - \else - \ifnum\TABLEaction=\TABLEmidrow - \writestatus\m!TABLE{change \string\MR\space into \string\LR/\string\SR}% - \else\ifnum\TABLEaction=\TABLEfirstrow - \writestatus\m!TABLE{change \string\MR\space into \string\SR}% - \fi\fi - \startHLcommand - \expandafter\normalTABLEfullrule\@@tiHLheight - \stopHLcommand - \globalletempty\startHLcommand - \globalletempty\stopHLcommand - \accountTABLElinewidth - \fi - \setTABLEaction\TABLErule - \nobreak}} - -\let\startHLcommand\empty -\let\stopHLcommand \empty - -\def\TableHC - {\complexorsimpleTable{HC}} - -\def\complexTableHC[#1]% - {\TABLEnoalign - {\gdef\startHCcommand{\localstartcolor[#1]}% - \gdef\stopHCcommand {\localstopcolor}}% - \simpleTableHC} - -\def\simpleTableHC - {\TABLEnoalign - {\globallet\startHLcommand\startHCcommand - \globallet\stopHLcommand \stopHCcommand}% - \HL} - -%D \startitemize[3*ruim] -%D \sym{\type{\NL}} a vertical skip -%D \sym{\type{\NR}} goto the next row -%D \sym{\type{\NC}} goto the next column -%D \sym{\type{\FC}} a first column -%D \sym{\type{\MC}} a mid column -%D \sym{\type{\LC}} a last column -%D \stopitemize - -% n+1 uitleggen - -\def\defineTABLEsteps - {\let\NL\TableNL - \let\NR\TableNR - \let\NC\TableNC - \let\FC\TableNC - \let\MC\TableNC - \let\LC\TableNC} - -\def\TableNL - {\complexorsimpleTable{NL}} - -\def\complexTableNL[#1]% - {\TABLEnoalign - {\edef\@@tiNL{#1}% - \simpleTableNL}}% - -\def\simpleTableNL - {\TABLEnoalign - {\nobreak - \setbox0\vbox{\blank[\@@tiNL]}% - \vskip\ht0 - \nobreak}} - -\def\TableNR - {\ifnum\currentTABLEcolumn>\maxTABLEcolumn - \global\currentTABLEcolumn\zerocount - \normalTABLElineending - \else - \setTABLEerror\TABLEmissingcolumn - \handleTABLEerror - \fi - \TABLEnoalign - {\nobreak - \setTABLEaction\TABLEunknown}} - -\def\TableNC - {\checkTABLEautorow - \nextTABLEgrayline - \ifnum\currentTABLEcolumn>\maxTABLEcolumn - \setTABLEerror\TABLEmissingrow - \handleTABLEerror - \else - \global\advance\currentTABLEcolumn \plusone - \normalTABLEquote - \fi} - -% \bgroup -% \catcode`\|=\@@active -% \catcode`\"=\@@active -% \gdef\redefinetablebarandquote -% {\def|{\VL}% % \normalTABLEsimplebar -% \def\|##1{\VL[##1]}% % \normalTABLEcomplexbar -% \def"{\NC}} % \normalTABLEquote -% \egroup - -\let\redefinetablebarandquote\relax - -%D \startitemize[3*ruim] -%D \sym{\type{\DL}} -%D \sym{\type{\DV}} (\type{\VD}) -%D \sym{\type{\DC}} -%D \sym{\type{\DR}} -%D \stopitemize - -\newif\ifTABLEdivision - -% \def\defineTABLEdivisions -% {\global\TABLEdivisionfalse % in start -% \let\DL\TableDL -% \let\DC\TableDC -% \let\DV\TableDV -% \let\VD\TableDV -% \let\DR\TableDR} - -\def\defineTABLEdivisions - {\global\TABLEdivisionfalse % in start - \let\DL\TableDL - \let\DC\TableDC - \let\DV\TableDV - \let\DR\TableDR} - -\def\checkTABLEdivision - {\ifTABLEdivision \else - \chuckTABLEautorow - \global\currentTABLEcolumn\zerocount - \global\TABLEdivisiontrue - \fi} - -\def\TableDL - {\checkTABLEdivision - \complexorsimpleTable{DL}} - -\def\simpleTableDL - {\complexTableDL[1]} - -\def\complexTableDL[#1]% - {\ifnum\TABLEaction=\TABLErule - \writestatus\m!TABLE{skipping \string\DL}% - \else - \ifnum\TABLEaction=\TABLEmidrow - \writestatus\m!TABLE{change \string\MR\space into \string\LR/\string\SR}% - \else\ifnum\TABLEaction=\TABLEfirstrow - \writestatus\m!TABLE{change \string\MR\space into \string\SR}% - \fi\fi - \setTABLEaction=\TABLEunknown - \ifnum\currentTABLEcolumn>\maxTABLEcolumn - \setTABLEerror\TABLEmissingrow - \handleTABLEerror - \fi - %\startHLcommand - \ifnum#1=\plusone - \global\advance\currentTABLEcolumn \plustwo - \let\next\normalTABLEsinglerule - \else - \ifnum#1<\maxTABLEcolumn - \global\advance\currentTABLEcolumn \plusone - \def\next{\normalTABLEmultirule{#1}}% - \else - \setTABLEerror\TABLEdivisionoverflow - \let\next\handleTABLEerror - \fi - \fi - \next - %\stopHLcommand - %\globalletempty\startHLcommand - %\globalletempty\stopHLcommand - \fi} - -\def\TableDV - {\TableDCV\normalTABLEsimplebar} - -\def\TableDC - {\TableDCV\normalTABLEquote} - -\def\TableDCV#1% - {\checkTABLEdivision - \checkTABLEautorow - \ifnum\currentTABLEcolumn>\maxTABLEcolumn - \setTABLEerror\TABLEmissingrow - \handleTABLEerror - \else - \global\advance\currentTABLEcolumn \plusone - #1% - \fi} - -\def\TableDR - {\ifnum\currentTABLEcolumn<\maxTABLEcolumn % silent recovery - %\setTABLEerror\TABLEmissingcolumn % some day warning - %\handleTABLEerror - \finishTABLErow - \else - \global\currentTABLEcolumn\zerocount % nog check - \normalTABLElineending - \fi - \TABLEnoalign - {\nobreak - \global\TABLEdivisionfalse - \accountTABLElinewidth % temporary solution - \setTABLEaction\TABLErule}} - -\def\accountTABLElinewidth - {\scratchdimen\LineThicknessUnit} - -%D \startitemize[3*ruim] -%D \sym{\type{\BC}} -%D \sym{\type{\BR}} -%D \sym{\type{\BACKGROUND}} -%D \sym{\type{\CL}} -%D \sym{\type{\RL}} -%D \sym{\type{\BL}} -%D \sym{\type{\RASTER}} -%D \sym{\type{\COLOR}} -%D \stopitemize - -% definieer: \BC \BL -% herhaal: \BR -% definieer: \CL \RL (eerste \CL[green] = hele row! / \CL[1,green]) -% dus: \CL en \RL mix tussen \HL en \BL - -\def\defineTABLEbackgrounds - {\let\BC \TableBC - \let\BL \TableBL - \let\BR \TableBR - \let\BACKGROUND\TableBR - \let\CL \TableCL - \let\RL \TableRL - \let\COLOR \TableCOLOR - \let\RASTER \TableRASTER - \globallet\lastTABLEc\@@tibackgroundcolor - \globallet\lastTABLEr\@@tibackgroundscreen - \doifinsetelse\@@tibackground{c,color} % \v!color - {\global\chardef\TABLEcr\plusone} - {\global\chardef\TABLEcr\plustwo}} - -\def\TableBC - {\ifTABLEgrayline - \normalTABLEquote - \else - \TABLEnoalign\bgroup - \globallet\nextTABLEgrayline\executeTABLEgrayline - \globalletempty\TABLEgrayline % new - \let\BL\doTableBL - \let\BC\doTableBC - \expandafter\doTableBC - \fi} - -\def\doTableBC - {\addtoTABLEgrayline{\BC}% - \gobbleTableBCL} - -\def\TableBL - {\TABLEnoalign\bgroup - \globallet\nextTABLEgrayline\executeTABLEgrayline - \globalletempty\TABLEgrayline % new - \let\BL\doTableBL - \let\CL\doTableCL - \let\RL\doTableRL - \let\BC\doTableBC - \doTableBL} - -\def\doTableBL - {\complexorsimpleTable{BL}} - -\def\simpleTableBL - {\complexTableBL[,]} - -\def\complexTableBL[#1]% - {\analyzeTABLEcr[#1]% - \handleTABLEcr} - -\def\TableBR#1% - {\TABLEnoalign - {\globallet\nextTABLEgrayline\executeTABLEgrayline - \checkTABLEgrayline#1\BR - \global\TABLEgraylinetrue}} - -\def\analyzeTABLEcr[#1]% - {\doanalyzeTABLEcr[#1,,]} - -\def\doanalyzeTABLEcr[#1,#2,#3]% - {\doifnumberelse{#1x} % Is the x still needed here? - {\dodoanalyzeTABLEcr[#1,#2,#3]} - {\dodoanalyzeTABLEcr[1,#1,#2]}} - -\def\dodoanalyzeTABLEcr[#1,#2,#3]% - {\global\chardef\TABLEn#1\relax - \processaction - [#2] - [ c=>\global\chardef\TABLEcr1,% - color=>\global\chardef\TABLEcr1,% - r=>\global\chardef\TABLEcr2,% - raster=>\global\chardef\TABLEcr2]% - \ifcase\TABLEcr \or - \doifsomething{#3}{\xdef\lastTABLEc{#3}}% - \or - \doifsomething{#3}{\xdef\lastTABLEr{#3}}% - \fi} - -\def\handleTABLEcr - {\relax % else funny side effect - \ifcase\TABLEcr - % Can't happen! - \or - \addtoTABLEgrayline{\complexTableCOLOR[\the\TABLEn,\lastTABLEc]}% - \else - \addtoTABLEgrayline{\complexTableRASTER[\the\TABLEn,\lastTABLEr]}% - \fi - \gobbleTableBCL} - -\def\analyzeTABLEcrl#1[#2]% - {\doanalyzeTABLEcrl#1[#2,,]} - -\def\doanalyzeTABLEcrl#1[#2,#3,#4]% - {\doifnumberelse{#2x} % x ???????????????????? - {\dodoanalyzeTABLEcr[#2,#1,#3]} - {\dodoanalyzeTABLEcr[\ifTABLEgrayline1\else\maxTABLEcolumn\fi,#1,#2]}} - -\def\TableCL - {\TABLEnoalign\bgroup - \globallet\nextTABLEgrayline\executeTABLEgrayline - \globalletempty\TABLEgrayline % new - \let\BL\doTableBL - \let\CL\doTableCL - \let\RL\doTableRL - \let\BC\doTableBC - \doTableCL} - -\def\doTableCL - {\complexorsimpleTable{CL}} - -\def\simpleTableCL% nog eens \'e\'en lijn van maken - {\BL[\the\maxTABLEcolumn,c,\lastTABLEc]} - -\def\complexTableCL[#1]% - {\analyzeTABLEcrl{c}[#1]% - \handleTABLEcr} - -\def\TableRL - {\TABLEnoalign\bgroup - \globallet\nextTABLEgrayline\executeTABLEgrayline - \globalletempty\TABLEgrayline % new - \let\BL\doTableBL - \let\CL\doTableCL - \let\RL\doTableRL - \let\BC\doTableBC - \doTableRL} - -\def\doTableRL - {\complexorsimpleTable{RL}} - -\def\simpleTableRL - {\BL[\the\maxTABLEcolumn,r,\lastTABLEr]} - -\def\complexTableRL[#1]% - {\analyzeTABLEcrl{r}[#1]% - \handleTABLEcr} - -\def\checkTABLEgrayline#1#2% - {\!!doneatrue - \ifx#1\AR - \!!doneafalse - \else\ifx#1\SR\else\ifx#1\FR\else\ifx#1\MR\else\ifx#1\LR\else - \!!doneafalse - \fi\fi\fi\fi\fi - \if!!donea - \gdef\TABLEgraylinestatus - {[\string#1]}% - \gdef\TABLEendBCL - {#1}% - \else - \gdef\TABLEgraylineerror - {[\string#2\string#1->\string#2\string\SR]}% - \gdef\TABLEendBCL - {\SR}% - \fi} - -\def\endTABLErowGL#1#2#3% - {\ifcase#1\relax - % unknown - \or - \doPreTableGL\TABLErowfactor\TABLErowfactor - \or - \doPreTableGL\TABLErowfactor\TABLErowzero - \or - \ifnum\TABLEforce=\TABLEforcelastrow - \doPreTableGL\TABLErowzero\TABLErowfactor - \else\ifnum\TABLEforce=\TABLEforcefirstrow - \doPreTableGL\TABLErowfactor\TABLErowzero - \else - \doPreTableGL\TABLErowzero\TABLErowzero - \fi\fi - \or - \doPreTableGL\TABLErowzero\TABLErowfactor - \fi} - -\def\doPreTableGL#1#2% betere namen - {\xdef\OldLineThicknessFactor{\the\LineThicknessFactor}% - \xdef\OldLineThicknessUnit{\the\LineThicknessUnit}% - \global\LineThicknessFactor\plusone - \setbox0\hbox{\AugmentedTableStrut{#1}{#2}}% - \getboxheight\dimen0\of\box0\relax - \xdef\TABLEgraylineHeight{\the\dimen0}% - \global\LineThicknessUnit\TABLEgraylineHeight} - -\def\doPostTableGL - {\global\LineThicknessFactor\OldLineThicknessFactor - \global\LineThicknessUnit \OldLineThicknessUnit} - -% kan simpeler - -\def\docomplexTableCOLOR[#1]% - {\dodocomplexTableGL\localstartcolor \localstopcolor [#1,\lastTABLEc,,]} - -\gdef\docomplexTableRASTER[#1]% - {\dodocomplexTableGL\localstartraster\localstopraster[#1,\lastTABLEr,,]} - -\def\dodocomplexTableGL#1#2[#3,#4,#5,#6]% - {\doifelsenothing{#4}{#1[#5]}{#1[#4]}% - \doPreTableGL\TABLEendofrowheight\TABLEendofrowdepth - \ifnum#3=\plusone % else conflict with \omit in \= - \let\next\normalTABLEsinglerule - \else - \def\next{\normalTABLEmultirule{#3}}% - \fi - \next - \doPostTableGL - #2} - -\def\TableBACKGROUND - {\TableBR} - -\def\simpleTableRASTER #1{\docomplexTableRASTER[1]#1} -\def\complexTableRASTER[#1]{\docomplexTableRASTER[#1]} -\def\simpleTableCOLOR {\docomplexTableCOLOR [1]} -\def\complexTableCOLOR [#1]{\docomplexTableCOLOR [#1]} - -\def\TableRASTER{\complexorsimpleTable{RASTER}} -\def\TableCOLOR {\complexorsimpleTable{COLOR}} - -\def\addtoTABLEgrayline#1% - {\TABLEgraytoks\expandafter{\TABLEgrayline}% - \xdef\TABLEgrayline{\the\TABLEgraytoks\noexpand#1}} - -\def\setTableBCL#1#2% - {\ifx#1#2% - \gdef\TABLEgraylinestatus{[\string#1]}% - \gdef\TABLEendBCL{#1}% - \addtoTABLEgrayline{#1}% - \else - \gdef\TABLEgraylineerror{[\string#1->\string#2]}% - \gdef\TABLEendBCL{#2}% - \addtoTABLEgrayline{#2}% - \fi} - -\def\gobbleTableBCL#1% - {\ifx#1\BC \let\next\doTableBC \else - \ifx#1\BL \let\next\doTableBL \else - \ifx#1\SR \setTableBCL\SR\SR \let\next\egroup \else - \ifx#1\FR \setTableBCL\FR\FR \let\next\egroup \else - \ifx#1\MR \setTableBCL\MR\MR \let\next\egroup \else - \ifx#1\LR \setTableBCL\LR\LR \let\next\egroup \else - \setTableBCL #1\SR \let\next\egroup - \fi\fi\fi\fi\fi\fi - \next} - -\def\executeTABLEgrayline - {\TABLEnoalign - {\def\BC - {\advance\currentTABLEcolumn \plusone}% - \def\dodocomplexTableGL##1##2[##3,##4,##5,##6]% - {\BC\advance\currentTABLEcolumn ##3 }% - \let\endTABLErow\endTABLEgrayrow - \currentTABLEcolumn\zerocount - \TABLEgrayline\TABLEendBCL % determine n of columns and height - \advance\currentTABLEcolumn \minusone - \ifnum\currentTABLEcolumn>\maxTABLEcolumn - % error message too long line - \globalletempty\TABLEgrayline - \else - % \message{n of color columns: \the\currentTABLEcolumn}\wait - \global\TABLEgraylinetrue % vanaf hier nog checken - \fi - \global\currentTABLEcolumn\zerocount}% - \unskip\TABLEgrayline\TABLEendBCL - \TABLEnoalign - {\nobreak - \vskip-\TABLEgraylineHeight - \nobreak - \global\setTABLEactiontrue - \global\currentTABLEcolumn\zerocount - \globalletempty\nextTABLEgrayline - \global\TABLEgraydonetrue - \global\TABLEgraylinefalse}} - -\def\endTABLEgrayrow#1#2#3% - {\ifcase#1\relax - \global\chardef\TABLEendofrowheight\TABLErowfactor - \global\chardef\TABLEendofrowdepth \TABLErowfactor - \or - \global\chardef\TABLEendofrowheight\TABLErowfactor - \global\chardef\TABLEendofrowdepth \TABLErowfactor - \or - \global\chardef\TABLEendofrowheight\TABLErowfactor - \global\chardef\TABLEendofrowdepth \TABLErowzero - \or - \ifnum\TABLEforce=\TABLEforcelastrow - \global\chardef\TABLEendofrowheight\TABLErowzero - \global\chardef\TABLEendofrowdepth \TABLErowfactor - \else\ifnum\TABLEforce=\TABLEforcefirstrow - \global\chardef\TABLEendofrowheight\TABLErowfactor - \global\chardef\TABLEendofrowdepth \TABLErowzero - \else - \global\chardef\TABLEendofrowheight\TABLErowzero - \global\chardef\TABLEendofrowdepth \TABLErowzero - \fi\fi - \or - \global\chardef\TABLEendofrowheight\TABLErowzero - \global\chardef\TABLEendofrowdepth \TABLErowfactor - \fi} - -\def\defineTABLEshorthands% - {\def\SPAN##1{\use{##1}}% - \def\TWO {\use2}% - \def\THREE {\use3}% - \def\FOUR {\use4}% - \def\FIVE {\use5}% - \def\SIX {\use6}% - \def\REF {\ReFormat}} - -\def\defineTABLEunits - {\processaction - [\@@tidistance] - [ \v!none=>\OpenUp00\def\LOW{\Lower6 }, - \v!small=>\OpenUp00\def\LOW{\Lower6 }, % == baseline - \v!medium=>\OpenUp11\def\LOW{\Lower7 }, - \v!big=>\OpenUp22\def\LOW{\Lower8 }]% - \doifelse\@@tidistance\v!none - {\chardef\TABLErowfactor\zerocount} - {\chardef\TABLErowfactor\plustwo }} - -\def\dohandlebar % here ? - {\ifmmode - \@EA\domathmodebar - \else\ifintable - \@EAEAEA\domathmodebar - \else - \@EAEAEA\dotextmodebar - \fi\fi} - -% De macro's t.b.v. instellingen. - -\def\setuptables - {\dosingleargument\dosetuptables} - -\def\dosetuptables[#1]% - {\getparameters[\??ti][#1]% - \processaction - [\@@tialign] - [ \v!right=>\def\TABLEparalignment{\raggedright}, - \v!left=>\def\TABLEparalignment{\raggedleft}, - \v!middle=>\def\TABLEparalignment{\raggedcenter}, - \s!default=>\def\TABLEparalignment{\notragged}, - \s!unknown=>\def\TABLEparalignment{\notragged}]% - \assignalfadimension\@@tiVL\@@tiVLwidth 246% - \assignalfadimension\@@tiHL\@@tiHLheight246} - -\def\localTABLEsetup - {\@@ticommands\relax - \expanded{\switchtobodyfont[\@@tibodyfont]}% - \StrutHeightFactor 8 - \StrutDepthFactor 4 - \LineThicknessFactor4 - \NormalTLTU {.1pt}% - \NormalTSU {\normalbaselineskip\divide\StrutUnit 12 }% - \NormalTableUnits} - -%D And then I wrote the tabulate environment. That -%D alternative supports setting the rule thickness and color, -%D so here is the table alternative. - -\let\startglobalTABLEcolor\empty -\let\stopglobalTABLEcolor \empty - -\def\localTABLEsetup - {\@@ticommands\relax - % bodyfont - \expanded{\switchtobodyfont[\@@tibodyfont]}% - % linecolor - \doifsomething\@@tirulecolor - {\def\startglobalTABLEcolor{\localstartcolor[\@@tirulecolor]}% - \def\stopglobalTABLEcolor {\localstopcolor}}% - % linethickness - \LineThicknessFactor4 - \scratchdimen\@@tirulethickness - \divide\scratchdimen \LineThicknessFactor - \expanded{\NormalTLTU{\the\scratchdimen}}% - % spacing, was depth=4 height=8 (counters, sigh, now macros) - \doifelse\@@tiheight\v!strut - {\let\StrutHeightFactor\@@itheight} - {\let\StrutHeightFactor\@@tiheight}% - \doifelse\@@tidepth\v!strut - {\let\StrutDepthFactor\@@itdepth} - {\let\StrutDepthFactor\@@tidepth}% - \scratchdimen\StrutHeightFactor\points \multiply\scratchdimen 10% - \edef\StrutHeightFactor{\withoutpt\the\scratchdimen}% - \scratchdimen\StrutDepthFactor \points \multiply\scratchdimen 10% - \edef\StrutDepthFactor{\withoutpt\the\scratchdimen}% - % units - \NormalTSU{\normalbaselineskip\divide\StrutUnit 12 }% - \NormalTableUnits} - -\def\OpenUp#1#2% - {\scratchdimen\StrutHeightFactor \points \advance\scratchdimen #1\points - \edef\StrutHeightFactor{\withoutpt\the\scratchdimen}% - \scratchdimen\StrutDepthFactor \points \advance\scratchdimen #2\points - \edef\StrutDepthFactor{\withoutpt\the\scratchdimen}} - -%D As one can see, we didn't only add color, but also more -%D control over spacing. -%D -%D \startbuffer[a] -%D \starttable[|c|] -%D \HL -%D \VL \strut test \VL \FR -%D \VL \strut test \VL \MR -%D \VL \strut test \VL \MR -%D \VL \strut test \VL \LR -%D \HL -%D \stoptable -%D \stopbuffer -%D -%D \startbuffer[b] -%D \starttabulate[|c|] -%D \HL -%D \NC test \NC \NR -%D \NC test \NC \NR -%D \NC test \NC \NR -%D \NC test \NC \NR -%D \HL -%D \stoptabulate -%D \stopbuffer -%D -%D In the next example, the first table is defined as: -%D -%D \typebuffer[a] -%D -%D and the second one as: -%D -%D \typebuffer[b] -%D -%D The first table is typeset using the default height and -%D depth factors .8 and .4. The second table has both factors -%D set to \type {strut}, and the third table shows what -%D happens when we set the values to zero. The rightmost table -%D is typeset using the tabulate environment. -%D -%D \startcombination[4*1] -%D {$\vcenter{\getbuffer[a]}$} -%D {\hbox{h=.8 d=.4}} -%D {\setuptables[height=strut,depth=strut]$\vcenter{\getbuffer[a]}$} -%D {\hbox{h=d=\type{strut}}} -%D {\setuptables[height=0,depth=0]$\vcenter{\getbuffer[a]}$} -%D {\hbox{h=d=0}} -%D {$\vcenter{\getbuffer[b]}$} -%D {\hbox{tabulate}} -%D \stopcombination - -\setuptables - [HL=\v!medium, - VL=\v!medium, - NL=\v!small, - \c!frame=, - \c!align=\v!right, - \c!depth=.40, % \v!strut - \c!height=.80, % \v!strut - \c!rulethickness=\linewidth, - \c!rulecolor=, - \c!distance=\v!medium, - \c!bodyfont=\the\bodyfontsize, - \c!commands=, - \c!background=\v!screen, - \c!backgroundscreen=\@@rsscreen, - \c!backgroundcolor=, - \c!split=\v!auto] - -\def\ifintabel{\ifintable} % upward compatible - -\protect \endinput diff --git a/tex/context/base/core-tbl.tex b/tex/context/base/core-tbl.tex deleted file mode 100644 index a5d5a37da..000000000 --- a/tex/context/base/core-tbl.tex +++ /dev/null @@ -1,1436 +0,0 @@ -%D \module -%D [ file=core-tbl, -%D version=1998.11.03, -%D title=\CONTEXT\ Core Macros, -%D subtitle=Text Flow Tabulation, -%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 / Tabulation} - -% \processbetween gebruiken in head/tail macros - -\unprotect - -% WATCH OUT: don't change this model else trialtypesetting -% compatibility problems - -% watch out, cells expand pretty late on a per row basis - -% |p2|p3| 2:3 -% spanning - -% Be careful with changing the hsize calculation in p mode; -% the following code works quite well: -% -% \setupfield [line][location=low,height=1.2\lineheight,width=\hsize] -% \definefield [test] [line] [line] [] -% -% \starttabulate[|l|p|] -% \NC test \NC \field [test] \NC \NR -% \stoptabulate - -% In-text tabbing environment -% -% \starttabulate[| separated template] % eg [|l|p|] or [|l|p|p|] -% \NC ... \NC ... \NC\NR -% \stoptabulate -% -% with: two pass auto width calculation when no p-width -% specified, even with multiple p's, see examples. - -% TaBlE compatible specifications: -% -% l align column/paragraph left -% r align column/paragraph right -% c align column/paragraph center -% p p(dimen) of automatisch als alleen p -% w column width -% f font#1 -% B bold -% I italic -% S slanted -% T type -% R roman -% m math -% M display math -% h hook (inner level or par lines) -% b before (may be command#1) -% a after -% i i skip left of column -% j i skip right of column -% k i skip around column - -% s setups - -% g g{char} align at char -% . align at . -% , align at , - -% Still to be done - -% N math numbers (best hook into existing digits mechanism) -% n numbers (best hook into existing digits mechanism) -% Q math numbers (best hook into existing digits mechanism) -% q numbers (best hook into existing digits mechanism) -% ~ \hskip.5em -% | check - -% nesting - -% 10 evt auto stack; dan wel andere signal dan void nodig - -% present but not yet 100% ok -% -% \FL top hrule -% \ML mid hrule (with auto split) -% \LL bottom hrule -% \HL - -% \VL as soon as needed -% color as soon as needed - -% \EQ \RQ \HQ equal (raw, hook) -% \NC \RC \HC normal (raw, hook) -% -% \NR - -% \HR : rule with lineheight - -% \autotabulaterule : with lineheight, not first/last -% \autotabulateline : spaced, not first/last -% \tabulaterule : with lineheight -% \tabulateline : spaced - -% tricky: align scans ahead, over # and expands ones before -% while doing - -% new: -% -% \starttabulate[|cg{.}|cg{,}|cg{,}|] -% \NC period \NC comma \NC comma \NC\NR -% \NG 100.000,00 \NG 100.000,00 \NG 100,00 \NC\NR -% \NG 10.000,00 \NG 10.000,00 \NG 1000,00 \NC\NR -% \NG 100,00 \NG 100,00 \NG 10,00 \NC\NR -% \NG 10 \NG 10 \NG 0,00 \NC\NR -% \stoptabulate -% -% \starttabulate[|c.|c,|c,|] -% \NC period \NC comma \NC comma \NC\NR -% \NG 100.000,00 \NG 100.000,00 \NG 100,00 \NC\NR -% \NG 10.000,00 \NG 10.000,00 \NG 1000,00 \NC\NR -% \NG 100,00 \NG 100,00 \NG 10,00 \NC\NR -% \NG 10 \NG 10 \NG 0,00 \NC\NR -% \stoptabulate - -% nice demo (for BG) -% -% \starttabulate[|r|b{$\star$}|ra{\percent}|b{=}|r|] -% \NC 500 \NC \NC 60 \NC \NC 300 \NC \NR -% \NC 500 \NC \NC 55 \NC \NC 275 \NC \NR -% \NC 500 \NC \NC 50 \NC \NC 250 \NC \NR -% \NC 500 \NC \NC 45 \NC \NC 225 \NC \NR -% \NC 500 \NC \NC 40 \NC \NC 200 \NC \NR -% \NC 500 \NC \NC 35 \NC \NC 175 \NC \NR -% \NC 500 \NC \NC 30 \NC \NC 150 \NC \NR -% \NC 500 \NC \NC 25 \NC \NC 125 \NC \NR -% \NC 500 \NC \NC 20 \NC \NC 100 \NC \NR -% \stoptabulate - -\newtoks \tabulatepreamble -\newtoks \tabulatebefore -\newtoks \tabulateafter -\newtoks \tabulatebmath -\newtoks \tabulateemath -\newtoks \tabulatefont -\newtoks \tabulatesettings -\newtoks \tabulatedummy - -\newcount \nofautotabulate -\newcount \tabulatecolumns -\newcount \tabulatecolumn - -\newcount \tabulateminplines -\newcount \tabulatemaxplines - -\newif \ifautotabulate -\newif \ifsplittabulate \splittabulatetrue - -\newif \ifhandletabulatepbreak \handletabulatepbreaktrue -\newif \iftabulatenopbreak \tabulatenopbreakfalse - -\newif \iftabulateequal -\newif \iftracetabulate -\newif \ifframedtabulate - -\newdimen \tabulatepwidth -\newdimen \tabulatewidth -\newdimen \tabulateunit -\newdimen \tabulatemaxpheight - -\newbox \tabulatebox - -% [|lg{.}|] => \NG 12.34 \NC - -\gdef\handletabulatecharalign#1 % space delimited ! - {\edef\alignmentclass{\the\tabulatecolumn}% - \edef\alignmentcharacter{\getvalue{\@@tabalign@@\the\tabulatecolumn}}% - \ifcase\tabulatepass\or - \setfirstpasscharacteralign\checkalignment{#1}% - \fi % force hsize - \setsecondpasscharacteralign\checkalignment{#1}} - -\def\noftabcolumns{16} - -\def\@@tabbox@@ {@@tabbox@} -\def\@@tabhook@@ {@@tabhook@} -\def\@@tabalign@@ {@@tabalign@} -\def\@@tabsetups@@{@@tabsetups@} - -% \dorecurse\noftabcolumns % quick and dirty stack -% {\@EA\newbox\csname\@@tabbox@@\recurselevel\endcsname} - -\def\tablebox#1% - {\csname\@@tabbox@@\number#1\endcsname} - -% \def\checktablebox#1% -% {\ifundefinedelse{\@@tabbox@@\number#1}% -% \expandafter\newbox\csname\@@tabbox@@\number#1\endcsname -% \fi} - -\def\initializetablebox#1% also used elsewhere - {\ifcsname\@@tabbox@@\number#1\endcsname - \global\setbox\csname\@@tabbox@@\number#1\endcsname\box\voidb@x - \else - \expandafter\newbox\csname\@@tabbox@@\number#1\endcsname - \fi} - -% \def\initializetableboxes#1% hm, not that efficient, best make a simple dedicated tail recurser -% {\dorecurse#1{\initializetablebox\recurselevel}} - -\def\initializetableboxes#1% - {\scratchcounter#1\relax - \doinitializetableboxes} - -\def\doinitializetableboxes - {\ifnum\scratchcounter>\zerocount - \initializetablebox\scratchcounter - \advance\scratchcounter\minusone - \expandafter\doinitializetableboxes - \fi} - -\initializetableboxes\noftabcolumns - -\def\dotabulatenobreak - {\noalign - {\nobreak - \iftracetabulate - \red\hrule\!!height.5\linewidth\!!depth.5\linewidth - \par - \kern-\linewidth - \nobreak - \fi}} - -\let\notabulatehook\empty - -\def\checktabulatehook - {\ifnum\tabulatetype<\plustwo - \global\let\tabulatehook\notabulatehook - \else - \global\let\tabulatehook\dotabulatehook - \fi} - -\def\checktabulatesetups - {\getvalue{\@@tabsetups@@\the\tabulatecolumn}} - -\let\pretabrule \donothing -\let\posttabrule\donothing - -\def\dodosettabulatepreamble#1#2% - {\ifzeropt\tabulatewidth - \ifcase\tabulatemodus\relax - \let\preamblebox\empty - \else - \def\preamblebox{\autotabulatetrue}% - \fi - \else - \ifcase\tabulatemodus\relax - \edef\preamblebox{\hbox to \the\tabulatewidth}% - \else - \edef\preamblebox{\hsize\the\tabulatewidth}% - \fi - \fi - % - % less bytes - % - %\edef\preamblebox% - % {\ifcase\tabulatewidth - % \ifcase\tabulatemodus\relax\else\noexpand\autotabulatetrue\fi - % \els - % \ifcase\tabulatemodus\relax\hbox to\else\hsize\fi\the\tabulatewidth - % \fi}% - % - % 0 = NC column next EQ equal column - % 1 = RC column raw RQ equal column raw - % 2 = HC column hook HQ equal column hook - % some entries can be left out if we test for them being set - \@EA\appendtoks \@EA&\@EA\hskip\pretabskip\pretabrule##&\to\!!toksa - \appendtoks \ignorespaces\to\!!toksa - \@EA\appendtoks\@EA\global\@EA\tabulatecolumn\the\tabulatecolumns\relax\to\!!toksa - \appendtoks \checktabulatesetups\to\!!toksa - \appendtoks \checktabulatehook\to\!!toksa - \@EA\appendtoks \preamblebox\to\!!toksa - \appendtoks \bgroup\bbskip\bgroup#1\to\!!toksa - \appendtoks\ifnum\tabulatetype=\plusone \else \to\!!toksa - \@EA\appendtoks \the\tabulatebmath\to\!!toksa - \@EA\appendtoks \the\tabulatefont\to\!!toksa - \@EA\appendtoks \the\tabulatesettings\to\!!toksa - \@EA\appendtoks \the\tabulatebefore\to\!!toksa - \appendtoks\fi \to\!!toksa - \appendtoks \bgroup\ignorespaces\to\!!toksa - % - \appendtoks \tabulatehook##\to\!!toksa - % - %%\doifdefinedelse{\@@tabalign@@\tabulatecolumns} - %\doifdefinedelse{\@@tabalign@@\the\tabulatecolumns} - % {\appendtoks\handletabulatecharalign## \to\!!toksa} - % {\appendtoks\tabulatehook ##\to \!!toksa}% - % waarom kan ik hier geen \xx{##} geven, om een of - % andere reden passeert dan tex de hele regel (incl \NC's) - % als argument; elke delimiter <> space gaat trouwens fout - \appendtoks \unskip\unskip\ifmmode\else\endgraf\fi\egroup\to\!!toksa - \appendtoks\ifnum\tabulatetype=1 \else \to\!!toksa - \@EA\appendtoks \the\tabulateafter\to\!!toksa - \@EA\appendtoks \the\tabulateemath\to\!!toksa - \appendtoks\fi \to\!!toksa - \appendtoks #2\egroup\egroup\to\!!toksa - \@EA\appendtoks \@EA&\@EA\posttabrule\@EA\hskip\postabskip##\to\!!toksa - \appendtoks\NC\to\tabulatedummy - \let\bbskip\empty - \def\pretabskip{.5\tabulateunit}% - \let\postabskip\pretabskip - \let\gettabulateexit\dogettabulateexit - \tabulatewidth\zeropoint} - -% todo: we can speed up this module a bit -% -% \expanded{\!!toksa{\the\!!toksa -% &\hskip\pretabskip\noexpand\pretabrule####& -% \ignorespaces -% \global\tabulatecolumn\the\tabulatecolumns -% \noexpand\checktabulatesetups -% \noexpand\checktabulatehook -% \preamblebox -% \bgroup\noexpand\bbskip\bgroup\normalunexpanded{#1}% -% \noexpand\ifnum\tabulatetype=\plusone \noexpand\else -% \the\tabulatebmath -% \the\tabulatefont -% \the\tabulatesettings -% \the\tabulatebefore -% \noexpand\fi -% \bgroup\ignorespaces -% \noexpand\tabulatehook####% -% \unskip\unskip\noexpand\ifmmode\noexpand\else\endgraf\noexpand\fi\egroup -% \noexpand\ifnum\noexpand\tabulatetype=1 \noexpand\else -% \the\tabulateafter -% \the\tabulateemath -% \noexpand\fi -% \normalunexpanded{#2}\egroup\egroup -% &\noexpand\posttabrule\hskip\noexpand\postabskip####}}% - -\def\dosettabulatepreamble - {\ifx\next\relax - \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 - \else\ifx p\next \let\nextnext\gettabulateparagraph - \else\ifx s\next \let\nextnext\gettabulatesetups - \else\ifx w\next \let\nextnext\gettabulatewidth - \else\ifx f\next \let\nextnext\gettabulatefont - \else\ifx B\next \tabulatefont{\bf}% - \else\ifx I\next \tabulatefont{\it}% - \else\ifx S\next \tabulatefont{\sl}% - \else\ifx T\next \tabulatefont{\tt}% - \else\ifx R\next \tabulatefont{\rm}% - \else\ifx m\next \tabulatebmath{$}\tabulateemath{$}% - \else\ifx M\next \tabulatebmath{$\displaystyle}\tabulateemath{$}% - \else\ifx h\next \let\nextnext\gettabulatehook - \else\ifx b\next \let\nextnext\gettabulatebefore - \else\ifx a\next \let\nextnext\gettabulateafter - \else\ifx i\next \let\nextnext\gettabulatepreskip - \else\ifx j\next \let\nextnext\gettabulateposskip - \else\ifx k\next \let\nextnext\gettabulatepreposskip - \else\ifx X\next \let\nextnext\gettabulateexit % internal - \else\ifx e\next \appendtoks\global\tabulateequaltrue\to\tabulatesettings - \else\ifx ~\next \appendtoks\fixedspaces\to\tabulatesettings - \else\ifx g\next \let\nextnext\gettabulatealign - \else\ifx .\next \def\nextnext{\gettabulatealign.}% - \else\ifx ,\next \def\nextnext{\gettabulatealign,}% - \else \message{unknown preamble key [\meaning\next]}% - \fi\fi\fi\fi\fi \fi\fi\fi\fi\fi \fi\fi\fi\fi\fi - \fi\fi\fi\fi\fi \fi\fi\fi\fi\fi \fi\fi - \fi - \nextnext} - -\def\dogettabulateexit - {\let\postabskip\!!zeropoint - \settabulatepreamble} - -\let\gettabulateexit\dogettabulateexit - -\def\gettabulatepreskip#1% - {\doifnumberelse{#1} - {\scratchdimen#1\tabulateunit\let\next\empty} - {\scratchdimen.5\tabulateunit\def\next{#1}}% - \edef\pretabskip{\the\scratchdimen}% - \@EA\settabulatepreamble\next} - -\def\gettabulateposskip#1% - {\doifnumberelse{#1} - {\scratchdimen#1\tabulateunit\let\next\empty} - {\scratchdimen.5\tabulateunit\def\next{#1}}% - \edef\postabskip{\the\scratchdimen}% - \let\gettabulateexit\settabulatepreamble - \@EA\settabulatepreamble\next} - -\def\gettabulatepreposskip#1% - {\doifnumberelse{#1} - {\scratchdimen#1\tabulateunit\let\next\empty} - {\scratchdimen.5\tabulateunit\def\next{#1}}% - \edef\pretabskip{\the\scratchdimen}% - \let\postabskip\pretabskip - \let\gettabulateexit\settabulatepreamble - \@EA\settabulatepreamble\next} - -\def\gettabulatesetups#1% - {\setvalue{\@@tabsetups@@\the\tabulatecolumns}{\setups[#1]}% - \settabulatepreamble} - -\def\gettabulatehook#1% - {\setvalue{\@@tabhook@@\the\tabulatecolumns}{#1}% - \settabulatepreamble} - -\def\gettabulatealign#1% - {\setvalue{\@@tabalign@@\the\tabulatecolumns}{#1}% - \settabulatepreamble} - -\def\gettabulatebefore#1% - {\tabulatebefore{#1}% - \settabulatepreamble} - -\def\gettabulateafter#1% - {\tabulateafter{#1}% - \settabulatepreamble} - -\def\gettabulatefont#1% - {\tabulatefont{#1}% - \settabulatepreamble} - -\def\gettabulatewidth - {\chardef\tabulatemodus\zerocount - \chardef\tabulatedimen\zerocount - \doifnextcharelse(\dogettabulatewidth\settabulatepreamble} - -\def\gettabulateparagraph - {\doifnextcharelse{(} - {\chardef\tabulatemodus\plusone - \chardef\tabulatedimen\plusone - \dogettabulatewidth} - {\chardef\tabulatemodus\plustwo - \chardef\tabulatedimen\zerocount - \settabulatepreamble}} - -% \def\dogettabulatewidth(#1)% -% {\tabulatewidth#1\relax -% \ifnum\tabulatedimen=\plusone -% \global\advance\tabulatepwidth\tabulatewidth -% \fi -% \settabulatepreamble} - -% \def\dogettabulatewidth(#1)% -% {\doifelse{#1}\v!passend -% {\chardef\tabulatemodus\plusthree} -% {\tabulatewidth#1\relax}% -% \ifnum\tabulatedimen=\plusone -% \global\advance\tabulatepwidth\tabulatewidth -% \fi -% \settabulatepreamble} - -% \startbuffer -% \toplinebox{\framed[width=3cm,height=2cm]{tufte}} -% \stopbuffer -% \starttabulate[|p(fixed)|p|] -% \dorecurse{100}{\NC \getbuffer \NC test \par test \par \NC \NR} -% \stoptabulate -% \starttabulate[|p(fit)|p|] -% \dorecurse{100}{\NC \getbuffer \NC test \par test \par \NC \NR} -% \stoptabulate - -\def\dogettabulatewidth(#1)% - {\processallactionsinset - [#1]% - [ \v!fit=>\chardef\tabulatemodus\plusthree, - \v!fixed=>\chardef\tabulatemodus\plusthree - \tabulatenopbreaktrue, - \s!unknown=>\tabulatewidth#1\relax]% - \ifnum\tabulatedimen=\plusone - \global\advance\tabulatepwidth\tabulatewidth - \fi - \settabulatepreamble} - -\def\settabulatepreamble - {\afterassignment\dosettabulatepreamble\let\next=} - -\def\tabulateraggedright {\ifnum\tabulatetype=\plusone \else\raggedright \fi} -\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} - -\bgroup \catcode`\|=\@@other - -\gdef\nexttabulate#1|% - {\chardef\tabulatealign\@@tabulatealign - \chardef\tabulatemodus\zerocount - \chardef\tabulatedimen\zerocount - \tabulatebefore \emptytoks - \tabulateafter \emptytoks - \tabulatebmath \emptytoks - \tabulateemath \emptytoks - \tabulatefont \emptytoks - \tabulatesettings\emptytoks - \global\advance\tabulatecolumns\plusone - \letvalue{\@@tabsetups@@\the\tabulatecolumns}\donothing - \settabulatepreamble#1\relax\relax % permits i without n - \ifcase\tabulatemodus\relax - \ifcase\tabulatealign\relax - \dodosettabulatepreamble\empty \tabulatehss \or - \dodosettabulatepreamble\empty \tabulatehss \or - \dodosettabulatepreamble\tabulatehss\empty \or - \dodosettabulatepreamble\tabulatehss\tabulatehss \fi - \or % fixed width - \ifcase\tabulatealign\relax - \dodosettabulatepreamble \bskip \eskip \or - \dodosettabulatepreamble{\bskip\tabulateraggedright }\eskip \or - \dodosettabulatepreamble{\bskip\tabulateraggedleft }\eskip \or - \dodosettabulatepreamble{\bskip\tabulateraggedcenter}\eskip \fi - \or % auto width - \global\advance\nofautotabulate\plusone - \ifcase\tabulatealign\relax - \dodosettabulatepreamble \bskip \eskip \or - \dodosettabulatepreamble{\bskip\tabulateraggedright }\eskip \or - \dodosettabulatepreamble{\bskip\tabulateraggedleft }\eskip \or - \dodosettabulatepreamble{\bskip\tabulateraggedcenter}\eskip \fi - \or % simple - \dodosettabulatepreamble \xbskip \xeskip - \fi - \futurelet\next\donexttabulate} - -\egroup - -\def\donexttabulate - {\ifx\next\relax\else - \expandafter\nexttabulate - \fi} - -\def\splitofftabulatebox - {\dontcomplain - \global\setbox\tabulatebox % % % global ? % % % - \vsplit\tablebox\tabulatecolumn to \lineheight - \setbox\tabulatebox\normalvbox - {\unvbox\tabulatebox}% - \setbox\tabulatebox\hbox to \wd\tabulatebox - {\hss\dotabulatehook{\box\tabulatebox}\hss}% - \ht\tabulatebox\strutht - \dp\tabulatebox\strutdp - \box\tabulatebox} - -\def\dotabulatehook {\getvalue{\@@tabhook@@ \the\tabulatecolumn}} -\def\dotabulatealign {\getvalue{\@@tabalign@@ \the\tabulatecolumn}} - -\def\resettabulatepheight - {\global\tabulateminplines\plusone - \getnoflines\tabulatemaxpheight - \global\tabulatemaxplines\noflines - \global\tabulatemaxpheight\zeropoint} - -\def\settabulatepheight - {\scratchdimen\ht\tablebox\tabulatecolumn\relax - \ifdim\scratchdimen>\tabulatemaxpheight - \global\tabulatemaxpheight\scratchdimen - \fi} - -\def\handletabulatepbreak - {\TABLEnoalign - {\ifhandletabulatepbreak - \iftabulatenopbreak - \dotabulatenobreak - \else\ifnum\tabulatemaxplines>\plusone - \ifnum\tabulateminplines=\plusone - \dotabulatenobreak - \fi - \global\advance\tabulateminplines\plusone - \ifnum\tabulateminplines=\tabulatemaxplines\relax - \dotabulatenobreak - \fi - \fi \fi - \fi}} - -%D \startbuffer -%D \starttabulate[|c|p|p|] -%D \NC \bf Alpha \NC \bf Beta \NC \bf Gamma \NC\NR -%D \NC 1 \NC right indeed \NC definitely wrong \NC\NR -%D \NC 2 \NC \thinrules[n=3] \NC \thinrules[n=3] \NC\NR -%D \NC 3 \NC oh yes \NC simply no \NC\NR -%D \NC 4 \NC very true \NC as false as can be \NC\NR -%D \NC 5 \NC \thinrules[n=5] \NC \thinrules[n=5] \NC\NR -%D \NC 6 \NC \thinrules[n=3] \NC \thinrules[n=4] \NC\NR -%D \stoptabulate -%D \stopbuffer -%D -%D \typebuffer {\tracetabulatetrue\getbuffer} -%D -%D \startbuffer -%D \starttabulate[|c|p|p|] -%D \NC \bf Alpha \NC \bf Beta \NC \bf Gamma \NC\NR -%D \NC 1 \NC right indeed \NC definitely wrong \NC\NR -%D \NC 2 \NC oh yes \NC simply no \NC\NR -%D \NC 3 \NC very true \NC as false as can be \NC\NR -%D \NC 4 \NC the whole truth \NC but the truth \NC\NR -%D \stoptabulate -%D \stopbuffer -%D -%D \typebuffer {\tracetabulatetrue\getbuffer} - -% \definetabulate -% \redefinetabulate -% \starttabulate[preamble] -% \starttabulate -> \starttabulate[|l|p|] - -\bgroup \catcode`\|=\@@other - -\gdef\definetabulate - {\dotripleempty\dodefinetabulate} - -\gdef\dodefinetabulate[#1][#2][#3]% - {\ifthirdargument - \doifundefined{\??tt#1::\c!unit} - {\copyparameters - [\??tt#1::][\??tt\v!tabulate::]% - [\c!frame,\c!distance,\c!unit,\c!before,\c!bodyfont,\c!after, - \c!inner,\c!indenting,\c!margin,\c!align,\c!header,\c!title, - \c!rulecolor,\c!rulethickness,\c!split,EQ]}% - \copyparameters - [\??tt#1::#2][\??tt#1::]% - [\c!unit,\c!distance,\c!before,\c!bodyfont,\c!after, - \c!inner,\c!indenting,\c!frame,\c!split,\c!header,\c!title, - \c!margin,\c!align,\c!rulecolor,\c!rulethickness,EQ]% - \setvalue{\e!start#1::#2}{\dofinalstarttabulate[#1][#2][#3]}% - \setvalue{\e!start#1}{\bgroup\dosubstarttabulate[#1]}% - \letvalue{\??tt#1-\v!header}\empty - \letvalue{\??tt#1-\v!footer }\empty - \else\ifsecondargument - \definetabulate[#1][][#2]% - \else - \definetabulate[#1][][|l|p|]% - \fi\fi} - -\egroup - -\let\tabulateheadcontent\empty -\let\tabulatetailcontent\empty - -\newconditional\tabulatesomeamble - -\def\checkfulltabulatecontent % - needed, else confusion with \c!header - {\ifundefined{\??tt\currenttabulate-\v!header}% - \let\tabulateheadcontent\empty - \else - \def\tabulateheadcontent - {\TABLEnoalign{\global\settrue\tabulatesomeamble}% - \csname\??tt\currenttabulate-\v!header\endcsname - \TABLEnoalign{\global\setfalse\tabulatesomeamble}}% - \fi - \ifundefined{\??tt\currenttabulate-\v!footer}% - \let\tabulatetailcontent\empty - \else - \def\tabulatetailcontent - {\TABLEnoalign{\global\settrue\tabulatesomeamble}% - \csname\??tt\currenttabulate-\v!footer\endcsname - \TABLEnoalign{\global\setfalse\tabulatesomeamble}}% - \fi} - -% \def\fulltabulatecontent -% {\tabulateheadcontent -% \tabulatecontent -% \tabulatetailcontent} - -\def\fulltabulatecontent - {\tabulateheadcontent - \tabulatecontent - \tabulatetailcontent - \removefunnytabulateline} - -\def\removefunnytabulateline - {\ifhmode - \strut\crcr - \TABLEnoalign{\kern-\lineheight}% - \fi} - -\setvalue{\e!start\v!tabulatehead}% - {\dosingleempty\dostartstarttabulatehead} - -\def\dostartstarttabulatehead[#1]% - {\processcontent{\e!stop\v!tabulatehead}\next - {\letvalue{\??tt\iffirstargument#1\else\v!tabulate\fi::-\v!header}\next}} - -\setvalue{\e!start\v!tabulatetail}% - {\dosingleempty\dostartstarttabulatetail} - -\def\dostartstarttabulatetail[#1]% - {\processcontent{\e!stop\v!tabulatetail}\next - {\letvalue{\??tt\iffirstargument#1\else\v!tabulate\fi::-\v!footer}\next}} - -\def\dosubstarttabulate - {\dodoubleempty\dodosubstarttabulate} - -\def\dodosubstarttabulate[#1][#2]% - {\getvalue{\e!start#1::\ifundefined{\e!start#1::#2}\else#2\fi}} - -\setvalue{\e!start\v!tabulate}% - {\bgroup\dodoubleempty\donormalstarttabulate} - -\bgroup - -\gdef\donormalstarttabulate[#1][#2]% - {\ifsecondargument - \getparameters[\??tt\v!tabulate::][#2]% - \fi - \iffirstargument - \def\next{\dofinalstarttabulate[\v!tabulate][][#1]}% - \else - \def\next{\dofinalstarttabulate[\v!tabulate][][|l|p|]}% - \fi - \next} - -\egroup - -% The much neede hook: - -\newtoks\everytabulate - -% An example of its usage: - -\appendtoks \optimizeverbatimfalse \to \everytabulate -\appendtoks \chardef\recodeverbatimmode\plustwo \to \everytabulate - -% A status variable: - -\chardef\tabulatepass=0 - -\def\tabulateparameter#1{\csname\??tt\currenttabulate#1\endcsname} - -\bgroup - \catcode`\|=\@@other \gdef\@@otherbar{|} - \catcode`\|=\@@active \gdef\@@useotherbar{\let|\@@otherbar} -\egroup - -\def\dofinalstarttabulate[#1][#2][#3]% identifier sub preamble - {\edef\currenttabulate{#1::#2}% - \ifinsidefloat \else - \whitespace - \tabulateparameter\c!before - \fi - \bgroup - \resetcharacteralign - % todo: spacing around tabulate when bodyfont is set - % expansion en test needed ? - \splittabulatetrue - \processaction - [\tabulateparameter\c!split] - [% \v!yes=>\splittabulatetrue, - % \v!repeat=>\splittabulatetrue, % todo, default yes - \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 - \widowpenalty\zerocount % otherwise lines are not broken - \clubpenalty \zerocount % but overlap in funny ways - \the\everytabulate - \tabulateparameter\c!inner - \scratchdimen\leftskip - \advance\scratchdimen \hangindent - \doifvalue{\??tt\currenttabulate\c!indenting}\v!yes - {\advance\scratchdimen \parindent}% \ctxparindent - \edef\tabulateindent{\the\scratchdimen}% - \!!toksb\emptytoks - \def\dorepeat*##1##2% - {\dorecurse{##1}{\appendtoks##2\to\!!toksb}\do}% - \def\do - {\futurelet\next\dodo}% - \def\dodo % \@EAEAEA gebruiken - {\ifx\next\relax - % exit - \else\ifx*\next - \let\next\dorepeat - \else\ifx\bgroup\next - \let\next\dododo - \else - \let\next\dodododo - \fi\fi\fi - \next}% - \def\dododo##1% - {\appendtoks{##1}\to\!!toksb\do}% - \def\dodododo##1% - {\appendtoks##1\to\!!toksb\do}% - \global\tabulatecolumn\zerocount -% \do#3\relax -\bgroup\@@useotherbar\expanded{\egroup\noexpand\do#3\relax}% - \processcontent - {\e!stop#1}% \currenttabulate} - \tabulatecontent - {\@EA\processtabulate\@EA[\the\!!toksb]}} - -\chardef\tabulatetype=0 - -% 0 = NC column next EQ equal column -% 1 = RC column raw RQ equal column raw -% 2 = HC column hook HQ equal column hook - -\newif\iftabulatefirstflushed - -\def\tabulateEQ - {\iftabulatefirstflushed\else\tabulateparameter{EQ}\fi - \global\tabulateequalfalse} - -% \def\tabulatenormalcolumn#1% -% {&\iftabulateequal\tabulateEQ\fi&\global\chardef\tabulatetype#1&} -% -% \def\tabulateequalcolumn#1% -% {&\tabulateEQ&\global\chardef\tabulatetype#1&} -% -% however, \unskip en \ignorespaces permit usage in complex XML/\starttabulate - -\def\tabulatenormalcolumn#1% - {\unskip&\iftabulateequal\tabulateEQ\fi&\global\chardef\tabulatetype#1&% - \ignorespaces} - -\def\tabulateequalcolumn#1% - {\unskip&\tabulateEQ&\global\chardef\tabulatetype#1&% - \ignorespaces} - -\def\tabulateautocolumn - {\tabulatenormalcolumn\zerocount - \ifnum\tabulatecolumn>\tabulatecolumns\relax - \expandafter\NR - \else - \expandafter\ignorespaces % interferes with the more tricky hooks - \fi} - -\def\setquicktabulate#1% see \startlegend \startgiven - {\let#1\tabulateautocolumn - \let\\\tabulateautocolumn} - -%\def\dotabulateruleseperator -% {\vskip\strutdp} - -\def\dotabulateruleseperator % can be sped up - {\bgroup - \let\factor\!!plusone - \scratchskip\strutdp - \ExpandFirstAfter\processallactionsinset - [\tabulateparameter\c!distance] - [ \v!blank=>\scratchskip\bigskipamount, - \v!depth=>\scratchskip\strutdp, - \v!small=>\def\factor{.25}, - \v!medium=>\def\factor{.5}, - \v!big=>, - \v!none=>\scratchskip\zeropoint\def\factor{0}, - \v!grid=>\scratchskip\zeropoint\def\factor{0}, - \s!unknown=>\scratchskip\commalistelement]% - \scratchdimen\factor\scratchskip - \ifconditional\tabulatesomeamble\kern\else\vskip\fi\scratchdimen % new - \egroup} - -\def\dodotabulaterule#1% - {\color - [\tabulateparameter\c!rulecolor] - {\scratchdimen\tabulateparameter\c!rulethickness#1}} - -\def\dotabulaterule - {\dodotabulaterule - {\hrule\!!height.5\scratchdimen\!!depth.5\scratchdimen\relax - \doifvalue{\??tt\currenttabulate\c!distance}\v!grid - {\kern-\scratchdimen}}} % experimental tm-prikkels - -\def\dotabulatelinerule - {\multispan\totaltabulatecolumns % \multispan is a plain macro - % for the moment this one - \strut\hskip\tabulateparameter\c!margin - % neg values are ok ! - \hskip\tabulateindent % new august 2003 - \dodotabulaterule - {\!!heighta.5\lineheight - \advance\!!heighta-\strutdepth - \!!deptha-\!!heighta - \advance\!!deptha\scratchdimen - \leaders\hrule\!!height\!!heighta\!!depth\!!deptha\hfill}% - \cr} - -%D When set to true, no (less) break optimization is done. - -\newif\iftolerantTABLEbreak - -%D The main processing macro is large but splitting it up -%D would make things less clear. - -\def\doregistertabulateparoptions - {\iftrialtypesetting \else - \registerparoptions - \ifinsidefloat - % that is, an unbreakable one - \global\let\registertabulateparoptions\empty - \else - % unsafe in crossing pages, at each b... - % \global\let\registertabulateparoptions\empty - \fi - \fi} - -\appendtoks - \global\let\registertabulateparoptions\doregistertabulateparoptions -\to \everytabulate - -\newtoks\everytabulaterow - -\appendtoks - \registertabulateparoptions -\to \everytabulaterow - -\def\flushtabulateindent - {\ifnum\tabulatecolumn=\zerocount - \hbox to \tabulateindent - {% we now have a local hsize, and since we want to - % register positional info (i.e. real hsizes) we - % need to reconstitute the original hsize - \advance\hsize\tabulateindent - % this is indeed rather messy and took a few hours - % to dis/uncover - \the\everytabulaterow - \hss}% - \fi} - -\def\totaltabulatecolumns{0} - -\def\handletabulatedigits{\digits} - -%D Beware, we cannot use \type {\unexpanded} on \type {\HL} -%D cum suis, since \TEX's hard coded noalign lookahead fails -%D on it! I mistakenly added this for a while. - -\chardef\tabulaterepeathead\zerocount - -\newcount\noftabulatelines -\newcount\totalnoftabulatelines -\newcount\minusnoftabulatelines - -\setvalue{\??tt:\c!align:\v!normal}{0} -\setvalue{\??tt:\c!align:\v!right }{1} -\setvalue{\??tt:\c!align:\v!left }{2} -\setvalue{\??tt:\c!align:\v!middle}{3} - -\setvalue{\??tt:\c!header:\v!repeat}{\plusone} -\setvalue{\??tt:\c!header:\v!text }{\plustwo} - -\bgroup \catcode`\|=\@@other - -\gdef\processtabulate[|#1|]% in the process of optimizing - {\tabulateunit\tabulateparameter\c!unit - \checkfulltabulatecontent - \globallet\tabulateruledepth \!!zeropoint - \globallet\tabulateruleheight\!!zeropoint - \edef\@@tabulatealign{\executeifdefined{\??tt:\c!align:\tabulateparameter\c!align}0}% -% \ExpandFirstAfter\processaction % use \setalignmentswitch instead -% [\tabulateparameter\c!align] -% [ \v!normal=>\def\@@tabulatealign{0},% = default value -% \v!right=>\def\@@tabulatealign{1},% chardefs gebruiken -% \v!left=>\def\@@tabulatealign{2},% -% \v!middle=>\def\@@tabulatealign{3},% -% \s!default=>\def\@@tabulatealign{0},% -% \s!unknown=>\def\@@tabulatealign{0}]% - \let\pretabskip\!!zeropoint - \def\postabskip{.5\tabulateunit}% - \global\tabulatecolumns\zerocount - \global\nofautotabulate\zerocount - \global\noftabulatelines\zerocount - \totalnoftabulatelines\noftabulatelines - \minusnoftabulatelines\noftabulatelines - \global\tabulatepwidth\zeropoint - \global\tabulateequalfalse - \resettabulatepheight - \ifinsidesplitfloat - \donetrue - \else\ifinsidefloat - \donefalse - \else - \donetrue - \fi\fi - \ifdone - \chardef\tabulaterepeathead\executeifdefined{\??tt:\c!header:\tabulateparameter\c!header}\zerocount -% \processaction -% [\tabulateparameter\c!header] -% [\v!repeat=>\chardef\tabulaterepeathead\plusone, -% \v!text=>\chardef\tabulaterepeathead\plustwo]% - \fi - \unexpanded \def\NC{\tabulatenormalcolumn0}% - \unexpanded \def\RC{\tabulatenormalcolumn1}% - \unexpanded \def\HC{\tabulatenormalcolumn2}% - \unexpanded \def\EQ{\tabulateequalcolumn 0}% - \unexpanded \def\RQ{\tabulateequalcolumn 1}% - \unexpanded \def\HQ{\tabulateequalcolumn 2}% - \unexpanded \def\NG{\NC\handletabulatecharalign}% - \unexpanded \def\NN{\NC\handletabulatedigits}% new, undocumented, test first - \unexpanded \def\ND{\NC\handletabulatedigits}% same, for old times sake - \def\tabulaterule{\HR}% a rule with lineheight - \def\tabulateline{\HL}% just a spaced rule - \def\tabulateautorule{\doHR\plusone}% - \def\tabulateautoline{\doHL\plusone}% - \def\HR{\doHR\zerocount} - \def\HL{\doHL\zerocount} - \unexpanded \def\NR % next row - {\global\advance\noftabulatelines\plusone - \global\tabulatefirstflushedfalse - \global\tabulateequalfalse - \global\tabulatecolumn\zerocount - \resettabulatepheight - \unskip\unskip\crcr\flushtabulated - \TABLEnoalign - {\iftolerantTABLEbreak\else - \ifconditional\tabulatesomeamble \ifcase\tabulaterepeathead \else - \allowbreak - \fi \fi - \ifnum\noftabulatelines=\plusone - \dotabulatenobreak - \else\ifnum\noftabulatelines=\minusnoftabulatelines - \ifnum\tabulatemaxplines<\plustwo - \dotabulatenobreak - \else - \allowbreak % needed with pbreak prevention - \fi - \else - \allowbreak % needed with pbreak prevention - \fi\fi - \fi - \global\tabulatefirstflushedfalse}}% - \let\HL\empty % not needed - \let\SR\NR \let\AR\NR - \let\FL\empty \let\FR\NR - \let\ML\empty \let\MR\NR - \let\LL\empty \let\LR\NR - \let\doHR\gobbleoneargument - \let\doHL\gobbleoneargument - \global\let\flushtabulated\empty -% \let\savedbar|\let|\nexttabulate - \tabskip\zeropoint - \ifdim\tabulateparameter\c!margin>\zeropoint - \!!toksa{&\flushtabulateindent\strut##% - \tabskip\tabulateparameter\c!margin\strut - &##\tabskip\zeropoint}% - \else - \!!toksa{&\flushtabulateindent\strut##% - &##\tabskip\zeropoint}% - \fi - \tabulatewidth\zeropoint - % |#1X|\relax - \nexttabulate #1X|\relax - \scratchcounter\tabulatecolumns - \multiply\scratchcounter3% - \advance\scratchcounter4% - \edef\totaltabulatecolumns{\the\scratchcounter}% - \tabulatewidth\zeropoint - % \dorecurse\tabulatecolumns % can be made faster - % {\doifundefinedelse{\@@tabbox@@\recurselevel} - % {\expandafter\newbox\csname\@@tabbox@@\recurselevel\endcsname}% - % {\global\setbox\csname\@@tabbox@@\recurselevel\endcsname\box\voidb@x}}% - \initializetableboxes\tabulatecolumns - \appendtoks&##\to\!!toksa - \appendtoks\global\advance\tabulatecolumn\plusone\to\!!toksa - \appendtoks\NC\unskip\unskip\crcr\flushtabulated\to\tabulatedummy % no count - \global\tabulatecolumn\zerocount - \resettabulatepheight - \def\bskip - {\setbox\tabulatebox\vbox\bgroup - \global\let\tabulatehook\notabulatehook}% - \def\eskip - {\par\egroup - \global\let\tabulatehook\dotabulatehook}% - \def\xbskip - {\hbox\bgroup\vbox\bgroup - \global\let\tabulatehook\notabulatehook}% - \def\xeskip - {\par\egroup\egroup - \global\let\tabulatehook\dotabulatehook}% - % \let|\savedbar - \global\let\tabulatehook\dotabulatehook - \doifvalue{\??tt\currenttabulate\c!indenting}\v!no\forgetparindent - \ifinsidefloat - \let\tabulateindent\!!zeropoint - \else - \setlocalhsize \hsize\localhsize - \fi - \dontcomplain - \forgetall % hm, interference with \forgetparindent ^^^ probably bug, to be solved - \setbox0\vbox % outside \if because of line counting - {\notesenabledfalse - \let\tabulateindent\!!zeropoint - \trialtypesettingtrue % very important - \@EA\halign\@EA{\the\!!toksa\crcr\fulltabulatecontent\crcr}}% - \ifnum\nofautotabulate>\zerocount - % so, even if the natural size is larger, in the final - % run, we force the calculated width - \tabulatewidth\hsize - \advance\tabulatewidth -\wd0 - \advance\tabulatewidth -\tabulatepwidth - \ifnum\nofautotabulate>\zerocount - \divide\tabulatewidth \nofautotabulate\relax - \fi - \fi - \def\xbskip{\bskip}% - \def\xeskip{\eskip}% - \ifsplittabulate - \splittopskip\strutht - \global\let\flushtabulatedindeed\empty - \long\def\bbskip - {\ifvoid\tablebox\tabulatecolumn - \ifx\flushtabulatedindeed\empty\else - \setbox0\hbox - \fi - \fi}% - \def\bskip - {\ifvoid\tablebox\tabulatecolumn - \global\setbox\tablebox\tabulatecolumn\vbox - \bgroup - \global\let\tabulatehook\notabulatehook - \ifautotabulate\hsize\tabulatewidth\fi - % \begstrut % interferes with pre-\pars - % evt: \appendtoks\begstrut\to\everypar - \ignorespaces - \def\eskip - {\par\egroup - \settabulatepheight - \global\let\tabulatehook\dotabulatehook - \splitofftabulatebox}% - \else - \let\eskip\empty - \dontcomplain - \global\let\tabulatehook\dotabulatehook - \expandafter\splitofftabulatebox - \fi}% - \gdef\flushtabulated - {\TABLEnoalign % noalign % no interference ! - {\global\let\flushtabulatedindeed\empty - \global\tabulatecolumn\zerocount - \handletabulatepbreak - \dorecurse\tabulatecolumns % was: \noftabcolumns - {\ifvoid\tablebox\recurselevel\else - \gdef\flushtabulatedindeed{\the\tabulatedummy}% - \fi}% - \global\tabulatefirstflushedtrue}% - \flushtabulatedindeed}% - \else - % tabhook op alles ? - \def\bskip - {\vtop\bgroup - \ifautotabulate\hsize\tabulatewidth\fi - % \begstrut % interferes with pre-\pars - % evt: \appendtoks\begstrut\to\everypar - \ignorespaces}% - \def\eskip % vertical strut added august 2003 - {\par\verticalstrut\vskip-\struttotal\egroup}% - \fi - \totalnoftabulatelines\noftabulatelines - \minusnoftabulatelines\numexpr\noftabulatelines+\minusone\relax - \global\noftabulatelines\zerocount - \def\doHL##1% ##1 ignored - {\TABLEnoalign - {\csname - \ifnum\noftabulatelines=\zerocount F\else - \ifnum\noftabulatelines=\totalnoftabulatelines L\else - M\fi\fi - L\endcsname}}% - \def\doHR##1% horizontal rule line (break untested) - {\TABLEnoalign - {\globallet\TABLEautoline\dotabulatelinerule - \ifcase##1\or - \ifnum\noftabulatelines=\zerocount - \gdef\TABLEautoline{\TABLEnoalign{}}% - \else\ifnum\noftabulatelines=\totalnoftabulatelines - \gdef\TABLEautoline{\TABLEnoalign{}}% - \fi\fi - \fi - \dotabulatenobreak}% - \TABLEautoline - \TABLEnoalign - {\nobreak - \ifx\TABLEautoline\dotabulatelinerule\kern-\lineheight\fi - \ifnum\noftabulatelines=\totalnoftabulatelines - \@EA\dotabulatenobreak - \else - \@EA\allowbreak - \fi}% - \TABLEautoline - \TABLEnoalign - {\dotabulatenobreak}}% - \doifelsevalue{\??tt\currenttabulate\c!rule}\v!line - {\let\HL \HR - \let\tabulateautoline\tabulateautorule - \let\tabulateline \tabulaterule}% - {\def\HL{\doHL\zerocount}}% - \def\tablebaselinecorrection - {\def\dobaselinecorrection - {\vskip-\prevdepth - \vskip\strutdp - \vskip\strutdp}% - \baselinecorrection}% - \def\FL{\TABLEnoalign - {\ifinsidefloat\else - \doifemptyvalue{\??tt\currenttabulate\c!before} % no expansion - {\tablebaselinecorrection}% - \fi - \dotabulaterule - \dotabulatenobreak - \dotabulateruleseperator - \prevdepth\strutdp - \dotabulatenobreak}}% - \def\ML{\TABLEnoalign - {\dotabulateruleseperator - \dotabulaterule - \ifnum\noftabulatelines>\plusone - \ifnum\noftabulatelines<\minusnoftabulatelines - \vskip\topskip\allowbreak\vskip-\topskip - \vskip-\tabulateparameter\c!rulethickness - \dotabulaterule - \fi - \fi - \dotabulateruleseperator}}% - \def\LL{\TABLEnoalign - {\dotabulatenobreak - \dotabulateruleseperator - \dotabulatenobreak - \dotabulaterule - \ifinsidefloat\else - \doifemptyvalue{\??tt\currenttabulate\c!after} % no expansion - {\vskip\strutdp - \verticalstrut - \vskip-\struttotal}% - \fi}}% - \chardef\tabulatepass\plustwo - % - \ifcase\tabulaterepeathead - \ifinsidesplitfloat - \setbox\tabulatebox\vbox \bgroup - \else - \startframedcontent[\tabulateparameter\c!frame]% - \fi - \else - \setbox\tabulatebox\vbox \bgroup - \fi - % - \@EA\halign\@EA{\the\!!toksa\crcr\fulltabulatecontent\crcr}% - \prevdepth\strutdp % nog eens beter, temporary hack - \doifvalue{\??tt\currenttabulate\c!distance}\v!grid - {\vskip-\strutdp}% experimental tm-prikkels - % - \ifcase\tabulaterepeathead - \ifinsidesplitfloat - \egroup \splittabulatebox\tabulatebox - \else - \stopframedcontent - \fi - \else - \egroup \splittabulatebox\tabulatebox - \fi - % - \egroup - \ifinsidefloat \else - \tabulateparameter\c!after - \fi - \egroup} - -\egroup - -% \setuptabulate[split=yes,header=text,title=Vervolg van Tabel] -% -% % \starttabulatehead -% % \NC test \NC hans\NC \NR -% % \stoptabulatehead -% -% \starttabulate -% \NC test \NC \input tufte \relax \NC \NR -% \NC test \NC \input knuth \relax \NC \NR -% \NC test \NC \input knuth \relax \NC \NR -% \NC test \NC \input tufte \relax \NC \NR -% \NC test \NC \input tufte \relax \NC \NR -% \NC test \NC \input tufte \relax \NC \NR -% \stoptabulate - -% \def\splittabulatebox#1% #1 <> 0/2 / derived from the one in core-ntb.tex -% {\ifinsidefloat -% \unvbox#1% -% \else -% \ifcase\tabulaterepeathead\or -% \setbox2\copy#1% -% \setbox2\vsplit2 to \lineheight -% \setbox2\vbox{\unvbox2}% -% \fi -% \doloop -% {\setbox0\vsplit#1 to \onepoint % \lineheight -% \ifdim\pagegoal<\maxdimen -% \donetrue -% \else\ifdim\pagetotal=\zeropoint -% \donetrue -% \else -% \donefalse -% \fi\fi -% \ifdone -% \setbox0\vbox{\unvbox0}% -% \dimen0\pagetotal -% \advance\dimen0\dp0 -% \advance\dimen0\ht0 -% \ifdim\dimen0>\pagegoal -% \bgroup \page \egroup % make sure that local vars are kept -% \ifcase\tabulaterepeathead\or -% \unvcopy2 -% \or -% \hbox{\strut\tabulateparameter\c!title}% -% \fi -% \fi -% \fi -% % test this on icare checklists / quite hacky ! ! ! -% \ifdim\ht0>\tabulateparameter\c!rulethickness\else -% \kern-2\ht0 % brrrr -% \fi -% % -% \unvbox0 -% \allowbreak -% \ifvoid#1 \exitloop \fi}% -% \fi} - -\def\splittabulatebox#1% #1 <> 0/2 / derived from the one in core-ntb.tex - {\ifinsidesplitfloat - \dosplittabulatebox#1% - \else\ifinsidefloat - \unvbox#1% - \else - \dosplittabulatebox#1% - \fi\fi} - -\def\dosplittabulatebox#1% - {\resettsplit - \def\tsplitminimumfreelines{2}% - \def\tsplitminimumfreespace{0pt}% - \setbox\tsplitcontent\box#1% - \ifcase\tabulaterepeathead\or - \setbox\tsplithead\vsplit\tsplitcontent to \lineheight - \setbox\tsplithead\vbox{\unvbox\tsplithead}% - \or - \setbox\tsplithead\vbox{\hbox{\strut\tabulateparameter\c!title}}% - \fi - \handletsplit} - -%D \starttyping -%D \setuptabulate[split=no,rule=line] -%D -%D \starttabulate -%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule -%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule -%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule -%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule -%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule -%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule -%D \stoptabulate -%D \stoptyping - -% \starttabulatie[|mc|] -% \NC \digits{100.000,00} \NC\NR -% \NC \digits{@10.000,00} \NC\NR -% \NC \digits{@@@.100,00} \NC\NR -% \NC \digits{@@@.@10,@@} \NC\NR -% \NC \digits{@@@.@@1,@@} \NC\NR -% \stoptabulatie -% -% \starttabulatie[|mc|] -% \ND 100.000,00 \NC\NR -% \ND @10.000,00 \NC\NR -% \ND @@@.100,00 \NC\NR -% \ND @@@.@10,@@ \NC\NR -% \ND @@@.@@1,@@ \NC\NR -% \stoptabulatie -% -% \starttabulatie[|c|] -% \ND $100.000,00$ \NC\NR -% \ND $@10.000,00$ \NC\NR -% \ND $@@@.100,00$ \NC\NR -% \ND $@@@.@10,@@$ \NC\NR -% \ND $@@@.@@1,@@$ \NC\NR -% \stoptabulatie -% -% \starttabulatie[|c|] -% \NC $\digits 100.000,00 $ \NC\NR -% \NC $\digits @10.000,00 $ \NC\NR -% \NC $\digits @@@.100,00 $ \NC\NR -% \NC $\digits @@@.@10,@@ $ \NC\NR -% \NC $\digits @@@.@@1,@@ $ \NC\NR -% \stoptabulatie -% -% \starttabulatie[|c|] -% \NC \digits $100.000,00$ \NC\NR -% \NC \digits $@10.000,00$ \NC\NR -% \NC \digits $@@@.100,00$ \NC\NR -% \NC \digits $@@@.@10,@@$ \NC\NR -% \NC \digits $@@@.@@1,@@$ \NC\NR -% \stoptabulatie - -\def\setuptabulate - {\dotripleempty\dosetuptabulate} - -\def\dosetuptabulate[#1][#2][#3]% - {\ifthirdargument - \getparameters[\??tt#1::#2][#3]% - \else\ifsecondargument - \getparameters[\??tt#1::][#2]% - \else - \getparameters[\??tt\v!tabulate::][#1]% - \fi\fi} - -\setuptabulate - [\c!unit=1em, - EQ={:}, - \c!frame=\v!off, - \c!bodyfont=, - \c!rule=\v!normal, - \c!rulecolor=, - \c!rulethickness=\linewidth, - \c!inner=, - \c!before=\blank, - \c!after=\blank, - \c!distance={\v!depth,\v!medium}, - \c!align=\v!normal, - \c!margin=\!!zeropoint, - \c!split=\v!auto, - \c!header=\v!yes, - \c!title=, - \c!indenting=\v!no] - -\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-tsp.tex b/tex/context/base/core-tsp.tex deleted file mode 100644 index e9f0e7d58..000000000 --- a/tex/context/base/core-tsp.tex +++ /dev/null @@ -1,427 +0,0 @@ -%D \module -%D [ file=core-tsp, -%D version=2000.10.20, -%D title=\CONTEXT\ Core Macros, -%D subtitle=Splitting 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. - -\writestatus{loading}{Context OTR Macros / Floating Bodies} - -%D The code in this file is move here from other places. - -\unprotect - -% only to be used with single tokens (will be prim) - -\ifx\htdp\undefined \def\htdp#1{\dimexpr\ht#1+\dp#1\relax} \fi - -%D Although the name resembles floats, and therefore this should be -%D a page module, we decided to make it core functionality because the -%D table code depends on it. Othrwise there would be too much -%D overloading afterwards involved. Actually, the float part is rather -%D generic and not that related to floats. - -% \splitfloat [settings] {\placetable[optional args]{test}} {content} - -\definenumber - [\??si] - [\c!way=\v!by\v!text, - \c!conversion=\@@siconversion] - -\def\setupfloatsplitting - {\dodoubleargument\getparameters[\??si]} - -\newif\ifinsidesplitfloat % will become chardef - -\newtoks \everysplitfloatsetup - -\def\splitfloat - {\dosingleempty\dosplitfloat} - -\ifx\floatcaptionsuffix\undefined \else - \let\floatcaptionsuffix\empty % will become \splitfloatcaptionsuffix -\fi - -\def\extrasplitfloatlines{0} - -\def\dosplitfloat[#1]#2% nog dubbele refs - {\bgroup - \global\setfalse\splitfloatdone - \aftergroup\checksplitfloat - \insidefloattrue - \insidesplitfloattrue - \getparameters[\??si][#1]% - \resetnumber[\??si]% - \def\floatcaptionsuffix{\convertednumber[\??si]}% - \let\extrasplitfloatlines\@@silines - \the\everysplitfloatsetup - \def\splitfloatcommand{#2}% - \global\settrue \onlyonesplitofffloat - \global\setfalse\somenextplitofffloat - \dopushsavedfloats - \@@sibefore - \let\next} % \bgroup - -\def\checksplitfloat - {\ifconditional\splitfloatdone\else - \blank{\tttf \getmessage\m!floatblocks{13}\empty}\blank - \showmessage\m!floatblocks{13}\empty - \fi} - -\settrue \onlyonesplitofffloat -\setfalse\somenextplitofffloat - -%D When \type {inbetween} is made empty instead of the -%D default \type {\page}, we will get delayed flushing -%D and text may continue below the graphic. -%D -%D \starttyping -%D \dorecurse{2}{\input tufte } -%D -%D \splitfloat[lines=auto,inbetween=] -%D {\placetable{\dorecurse{5}{test\recurselevel\endgraf}}} -%D {\bTABLE[split=yes] -%D \bTR \bTD 11 \eTD \bTD \input tufte \eTD \eTR -%D \bTR \bTD 12 \eTD \bTD \input zapf \eTD \eTR -%D \bTR \bTD 13 \eTD \bTD \input bryson \eTD \eTR -%D \bTR \bTD 14 \eTD \bTD test \eTD \eTR -%D \bTR \bTD 21 \eTD \bTD \input tufte \eTD \eTR -%D \bTR \bTD 22 \eTD \bTD \input zapf \eTD \eTR -%D \bTR \bTD 23 \eTD \bTD \input bryson \eTD \eTR -%D \bTR \bTD 24 \eTD \bTD test \eTD \eTR -%D \bTR \bTD 31 \eTD \bTD \input tufte \eTD \eTR -%D \bTR \bTD 32 \eTD \bTD \input zapf \eTD \eTR -%D \bTR \bTD 33 \eTD \bTD \input bryson \eTD \eTR -%D \bTR \bTD 34 \eTD \bTD test \eTD \eTR -%D \eTABLE} -%D -%D \dorecurse{10}{\input tufte } -%D \stoptyping - -\newconditional\splitfloatdone - -\def\dodowithsplitofffloat - {\dowithnextbox - {\forgetall - \dontcomplain - \global\settrue\splitfloatdone - \chardef\nodelocationmode\zerocount % bypass auto-renumbering - \incrementnumber[\??si]% - \ifcase\rawnumber[\??si]\or \ifconditional\onlyonesplitofffloat - \let\floatcaptionsuffix\empty - \fi \fi - \bgroup - \ifconditional\somenextplitofffloat - \settrue\retainfloatnumber -\notesenabledfalse % best here, experimental, brrr; test with note in caption - \else - \setfalse\retainfloatnumber - \fi - \splitfloatcommand{\box\nextbox}% - \egroup - \ifconditional\somenextplitofffloat - \doifelsenothing\@@siinbetween - {\ifconditional\splitfloatfirstdone\else\page\fi} - \@@siinbetween - \else - \@@siafter - \dopopsavedfloats - \doflushsavedfloats - \fi - \global\settrue\splitfloatfirstdone}% - \vbox} - -\def\nodowithsplitofffloat - {\dowithnextbox - {\forgetall - \dontcomplain - \box\nextbox % maybe an option to unvbox - \global\settrue\splitfloatfirstdone}% - \vbox} - -\def\dochecksplitofffloat#1% box - {\ifinsidesplitfloat - \ifdim\ht#1=\zeropoint - \global\setfalse\somenextplitofffloat - \else - \global\settrue \somenextplitofffloat - \global\setfalse\onlyonesplitofffloat - \fi - \fi} - -\def\analyzesplitfloatcaption#1% depends on page-flt - {\doif\extrasplitfloatlines\v!auto - {\bgroup - \settrue\retainfloatnumber - \chardef\nodelocationmode\zerocount - \forcelocalfloats - \setuplocalfloats[\c!before=,\c!after=,\c!inbetween=]% - \splitfloatcommand{\hbox to \wd#1{\strut}}% dummy line - \setbox\scratchbox\vbox{\flushlocalfloats}% - \getnoflines{\ht\scratchbox}% - \resetlocalfloats - \advance\noflines\minusone % compensate dummy line - \expanded{\egroup\noexpand\edef\noexpand\extrasplitfloatlines{\the\noflines}}}} - -% \def\analyzesplitfloatcaption#1% -% {\edef\extrasplitfloatlines{11}} - -\def\dowithsplitofffloat % nextbox - {\ifinsidesplitfloat - \expandafter\dodowithsplitofffloat - \else - \expandafter\nodowithsplitofffloat - \fi} - -\def\doifnotinsidesplitfloat - {\ifinsidesplitfloat\expandafter\gobbleoneargument\fi} - -%D Some defaults: - -\setupfloatsplitting - [\c!conversion=\v!character, % \v!romannumerals - \c!lines=3, - \c!before=, - \c!inbetween=\page, - \c!after=] - -%D Table splitter, on top of previous code: - -\newbox\tsplitcontent -\newbox\tsplitresult -\newbox\tsplithead -\newbox\tsplitnext -\newbox\tsplittail - -\def\resettsplit{% only \def's starting a a new line are seen by the dep checker - \def\tsplitminimumfreelines{0}% - \def\tsplitminimumfreespace{0pt}% - \setbox\tsplitcontent \vbox{}% - \setbox\tsplitresult \vbox{}% - \setbox\tsplithead \vbox{}% - \setbox\tsplitnext \vbox{}% - \setbox\tsplittail \vbox{}% - \let\tsplitbeforeresult\donothing - \let\tsplitafterresult \donothing - \let\tsplitinbetween \donothing - \let\tsplitbefore \donothing - \let\tsplitafter \donothing - \let\postprocesstsplit \donothing -} - -\resettsplit - -% todo: keep tail to rest, so we need a lookahead - -\newconditional\splitfloatfirstdone - -\def\handletsplit - {\analyzesplitfloatcaption\tsplitcontent - \global\setfalse\splitfloatfirstdone - \testpagesync % new, sync, but still tricky - [\tsplitminimumfreelines] - [\dimexpr\tsplitminimumfreespace+\extrasplitfloatlines\lineheight\relax]% - \setbox\scratchbox\vbox{\tsplitinbetween}% - \edef\tsplitinbetweenheight{\the\htdp\scratchbox}% etex - \!!doneafalse - \doloop - {\ifinsidecolumns - % brrr, assumes empty columns - \global\setfalse\splitfloatfirstdone - \scratchdimen\textheight - \!!donectrue - \else - \ifconditional\splitfloatfirstdone - \scratchdimen\textheight - \!!donectrue - \else\ifdim\pagegoal<\maxdimen - \scratchdimen\dimexpr\pagegoal-\pagetotal\relax - \!!donecfalse - \else - \scratchdimen\textheight - \!!donectrue - \fi\fi - \fi - \scratchdimen\dimexpr\scratchdimen-\tsplitinbetweenheight-\tsplitminimumfreespace-\extrasplitfloatlines\lineheight\relax - \ifdim\htdp\tsplittail>\zeropoint - \advance\scratchdimen-\htdp\tsplittail - \fi - \setbox\tsplitresult\vbox - {\ifdim\ht\tsplithead>\zeropoint - \unvcopy\tsplithead - \tsplitinbetween - \fi}% - \if!!donea\else\ifdim\ht\tsplitnext>\zeropoint - \setbox\tsplithead\box\tsplitnext - \fi\fi - \!!doneatrue - \ifdim\ht\tsplitresult>\zeropoint - \!!donedtrue % table head - \else - \!!donedfalse % no tablehead - \fi - \splittopskip\zeropoint - \doloop - {\setbox\scratchbox\vsplit\tsplitcontent to \onepoint % \lineheight - \setbox\scratchbox\vbox{\unvbox\scratchbox}% - \ifdim\dimexpr\scratchdimen-\htdp\scratchbox-\htdp\tsplitresult\relax>\zeropoint - \setbox\tsplitresult\vbox - {\unvbox\tsplitresult - \tsplitinbetween - \unvbox\scratchbox}% - \ifvoid\tsplitcontent \exitloop \fi - \else\if!!doned - % we only have a tablehead so far - \setbox\tsplitresult\vbox{\unvbox\tsplitresult\unvbox\scratchbox}% - \exitloop - \else\if!!donec - % we have text height available, but the (one) cell is too - % large to fit, so, in order to avoid loops/deadcycles we do: - \setbox\tsplitresult\vbox - {\unvbox\tsplitresult - \tsplitinbetween - \unvbox\scratchbox}% - \exitloop - \else - \setbox\tsplitcontent\vbox - {\unvbox\scratchbox - \tsplitinbetween - \ifvoid\tsplitcontent\else\unvbox\tsplitcontent\fi}% - \exitloop - \fi\fi\fi - \!!donedfalse - \!!donecfalse}% - \postprocesstsplit - \dochecksplitofffloat\tsplitcontent - \ifvoid\tsplitcontent - \setbox\tsplitresult\vbox - {\unvbox\tsplitresult - \tsplitinbetween - \unvcopy\tsplittail}% - \dowithsplitofffloat{\tsplitbeforeresult\box\tsplitresult\tsplitafterresult}% - \doifnotinsidesplitfloat\tsplitafter - \endgraf - \exitloop - \else - % hack - \ifdim\pagegoal<\maxdimen - \global\pagegoal\dimexpr\pagegoal+\lineheight\relax % etex - \fi - % brrr - \ifdim\ht\tsplitresult>\zeropoint - \setbox\tsplitresult\vbox - {\unvbox\tsplitresult - \tsplitinbetween - \unvcopy\tsplittail}% - \dowithsplitofffloat{\tsplitbeforeresult\box\tsplitresult\tsplitafterresult}% - \doifnotinsidesplitfloat\tsplitafter - \endgraf - \fi - \ifinsidecolumns - \doifnotinsidesplitfloat\goodbreak - \else - \doifnotinsidesplitfloat\page - \fi - \fi}% - \global\setfalse\splitfloatfirstdone} % we can use this one for tests - -\protect \endinput - -% test cases - -% \setupTABLE[split=repeat] -% -% \input tufte \endgraf -% \splitfloat[lines=11] -% {\placetable{\dorecurse{10}{test\recurselevel\endgraf}}} -% {\bTABLE\dorecurse{100}{\bTR \bTD test \eTD \eTR}\eTABLE} -% \input tufte \page -% -% \input tufte \endgraf -% \splitfloat[lines=0] -% {} -% {\bTABLE\dorecurse{100}{\bTR \bTD test \eTD \eTR}\eTABLE} -% \input tufte \endgraf \page -% -% \input tufte \endgraf -% \bTABLE\dorecurse{100}{\bTR \bTD test \eTD \eTR}\eTABLE -% \input tufte \page - -% \setuptabulate[split=yes] -% -% \input tufte \endgraf -% \splitfloat[lines=11] -% {\placetable{\dorecurse{10}{test\recurselevel\endgraf}}} -% {\starttabulate\dorecurse{200}{\NC test \NC test \NC \NR}\stoptabulate} -% \input tufte \page -% -% \input tufte \endgraf -% \splitfloat[lines=0] -% {} -% {\starttabulate\dorecurse{200}{\NC test \NC test \NC \NR}\stoptabulate} -% \input tufte \page -% -% \input tufte \endgraf -% \starttabulate\dorecurse{200}{\NC test \NC test \NC \NR}\stoptabulate -% \input tufte \page - -% \setuptables[split=yes] -% -% \newtoks\TestToks -% -% \TestToks\emptytoks -% \appendtoks\starttablehead\to\TestToks -% \dorecurse{3}{\appendtoks\VL head \VL head \VL \SR\to\TestToks} -% \appendtoks\stoptablehead\to\TestToks -% \appendtoks\starttabletail\to\TestToks -% \dorecurse{3}{\appendtoks\VL tail \VL tail \VL \SR\to\TestToks} -% \appendtoks\stoptabletail\to\TestToks -% \appendtoks\starttables[|c|c|]\to\TestToks -% \dorecurse{100}{\appendtoks\VL test \VL test \VL \SR\to\TestToks} -% \appendtoks\stoptables\to\TestToks -% -% \input tufte \endgraf -% \splitfloat[lines=auto] % [lines=11] -% {\placetable{\dorecurse{10}{test\recurselevel\endgraf}}} -% {\the\TestToks} -% \input tufte \page -% -% \input tufte \endgraf -% \splitfloat[lines=0] -% {} -% {\the\TestToks} -% \input tufte \page -% -% \input tufte \endgraf -% \the\TestToks -% \input tufte \page -% -% multiple floats -% -% \starttext -% \dorecurse{3}{\input tufte } \endgraf -% \dorecurse{5}{\placefigure{}{\framed[height=.5\textheight]{}}} -% \splitfloat[lines=auto,inbetween=] -% {\placetable{\dorecurse{5}{test\recurselevel\endgraf}}} -% {\bTABLE[split=yes] -% \bTR \bTD 11 \eTD \bTD \input tufte \eTD \eTR -% \bTR \bTD 12 \eTD \bTD \input zapf \eTD \eTR -% \bTR \bTD 13 \eTD \bTD \input bryson \eTD \eTR -% \bTR \bTD 14 \eTD \bTD test \eTD \eTR -% \bTR \bTD 21 \eTD \bTD \input tufte \eTD \eTR -% \bTR \bTD 22 \eTD \bTD \input zapf \eTD \eTR -% \bTR \bTD 23 \eTD \bTD \input bryson \eTD \eTR -% \bTR \bTD 24 \eTD \bTD test \eTD \eTR -% \bTR \bTD 31 \eTD \bTD \input tufte \eTD \eTR -% \bTR \bTD 32 \eTD \bTD \input zapf \eTD \eTR -% \bTR \bTD 33 \eTD \bTD \input bryson \eTD \eTR -% \bTR \bTD 34 \eTD \bTD test \eTD \eTR -% \eTABLE} -% \dorecurse{10}{\input tufte } -% \stoptext 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.

--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--

Variables are saved using in the previously defined table and passed @@ -32,39 +33,206 @@ directly access the variable using a call.

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

..

) -\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

..

+\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{ 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} \par \type<<....>> \par \type<<..<>..>> \par +% normal: \par \type{xx<..xx.. >..>xx} \par \type{<....>} \par \type{<....>} +% \setuptype[option=slanted] +% slanted: \par \type{xx<<..sl..<> xx>>..sl..>>xx} \par \type<<..xx..>> \par \type<<..<>..>> \par +% slanted: \par \type{xx<<..sl.. xx>..sl..>>xx} \par \type<<..xx..>> \par \type<<....>> \par +% \setuptype[option=none] +% none: \par \type{xx<<..xx..<> >>..>>xx} \par \type<<....>> \par \type<<..<>..>> \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{ 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} \par \type<<....>> \par \type<<..<>..>> \par +% normal: \par \type{xx<..xx.. >..>xx} \par \type{<....>} \par \type{<....>} +% \setuptype[option=slanted] +% slanted: \par \type{xx<<..sl..<> xx>>..sl..>>xx} \par \type<<..xx..>> \par \type<<..<>..>> \par +% slanted: \par \type{xx<<..sl.. xx>..sl..>>xx} \par \type<<..xx..>> \par \type<<....>> \par +% \setuptype[option=none] +% none: \par \type{xx<<..xx..<> >>..>>xx} \par \type<<....>> \par \type<<..<>..>> \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{ 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} \par \type<<....>> \par \type<<..<>..>> \par -% normal: \par \type{xx<..xx.. >..>xx} \par \type{<....>} \par \type{<....>} -% \setuptype[option=slanted] -% slanted: \par \type{xx<<..sl..<> xx>>..sl..>>xx} \par \type<<..xx..>> \par \type<<..<>..>> \par -% slanted: \par \type{xx<<..sl.. xx>..sl..>>xx} \par \type<<..xx..>> \par \type<<....>> \par -% \setuptype[option=none] -% none: \par \type{xx<<..xx..<> >>..>>xx} \par \type<<....>> \par \type<<..<>..>> \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-- +

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).

+ +

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.

+ +

Examples of usage can be found in the font related code.

+--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("\n") + f:write("\n") + if jobname then + f:write(format("\t%s\n",jobname)) + end + f:write("\t\n") + for _,v in ipairs(table.sortedkeys(found)) do + f:write(format("\t\t%s\n",found[v],v)) + end + f:write("\t\n") + f:write("\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-- +

This file is used when we want the input handlers to behave like +kpsewhich. What to do with the following:

+ + +{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c} +$SELFAUTOLOC : /usr/tex/bin/platform +$SELFAUTODIR : /usr/tex/bin +$SELFAUTOPARENT : /usr/tex + + +

How about just forgetting about them?

+--ldx]]-- + +local suffixes = resolvers.suffixes +local formats = resolvers.formats + +suffixes['gf'] = { 'gf' } +suffixes['pk'] = { '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-- +

If you wondered abou tsome of the previous mappings, how about +the next bunch:

+--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-- +

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.

+ + +TEXMFCACHE=$TMP;$TEMP;$TMPDIR;$TEMPDIR;$HOME;$TEXMFVAR;$VARTEXMF;. + + +

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.

+--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 +% +% Ϭ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 -% -% \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.

--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.

--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.

--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.mkiv b/tex/context/base/font-col.mkiv new file mode 100644 index 000000000..22a67ac8e --- /dev/null +++ b/tex/context/base/font-col.mkiv @@ -0,0 +1,146 @@ +%D \module +%D [ file=font-col, +%D version=2008.06.11, +%D title=\CONTEXT\ Font Macros, +%D subtitle=Fallbacks (collections), +%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. + +% ! EXPERIMENTAL ! code will be made more nice + +% todo: missing only, force always, multiple fallbacks with test, scale +% +% \resetfontfallback [whatever] +% +% \definefontfallback [whatever] [Slanted] [0x0060-0x007F] [force=yes] +% \definefontfallback [whatever] [Bold] [0x0080-0x00FF,0x00A0-0x00AF] [rscale=1.2] +% \definefontfallback [whatever] [BoldSlanted] [0x00C0-0x00C7] [check=yes,force=yes] + +\writestatus{loading}{ConTeXt Font Macros / Collections} + +\registerctxluafile{font-col}{1.001} + +\unprotect + +\def\definefontfallback + {\doquadrupleempty\dodefinefontfallback} + +\def\dodefinefontfallback[#1][#2][#3][#4]% + {\ctxlua{fonts.collections.define("#1","#2",\!!bs#3\!!es,\!!bs#4\!!es)}} + +\def\resetfontfallback + {\dodoubleempty\doresetfontfallback} + +\def\doresetfontfallback[#1][#2]% + {\ctxlua{fonts.collections.reset("#1","#2")}} + +% add fallbacks to last font + +\def\dodefinefontfallbacks#1% + {\ctxlua{fonts.collections.prepare("#1")}} + +% we might as well move the handling to lua but then we need to pass the +% fallbacks, skewchar etc. + +\setfalse\doingfontfallbacks + +\def\dodefinefontfallbacksindeed#1% + {\begingroup + \settrue\doingfontfallbacks + \lastrawfontcall % sets current font id + \dodefinefontfallbacks#1% + \endgroup} + +\appendtoks + \ifconditional\doingfontfallbacks\else + \ifx\@@fontfallbacks\empty + \ifx\@@fontclassfallbacks\empty + \else + \dodefinefontfallbacksindeed\@@fontclassfallbacks + \fi + \else + \dodefinefontfallbacksindeed\@@fontfallbacks + \fi + \fi +\to\everydefinefont + +\def\dostartcloningfonts + {\bgroup + \let\savedfontspec\somefontspec} + +\def\dostopcloningfonts + {\egroup} + +\def\doclonefonta#1#2% kind of dododefinefont + {\ctxlua{fonts.collections.message("defining #1 (relative scale: #2)")}% + \autofontsizefalse + \let\lastfontidentifier\s!dummy + \def\localrelativefontsize{#2}% + \let\localabsolutefontsize\fontbody + \lowleveldefinefont{#1}\rawfontidentifier + \csname\rawfontidentifier\endcsname + \autofontsizefalse + %\setfontcharacteristics + }%\the\everyfontswitch} + +\def\doclonefontb#1% #2 + {\doclonefonta{#1 \savedfontspec}} + +% check : only replace when present in replacement font (default: no) +% force : force replacent even when basefont has glyph (default: yes) + +% \definefontfallback [whatever] [Slanted] [0x0060-0x007F] [force=yes] +% \definefontfallback [whatever] [Bold] [0x0080:0x00FF,0x00A0:0x00AF] [rscale=2.0] +% \definefontfallback [whatever] [BoldSlanted] ["00C0-"00C7] [check=yes,force=yes] +% \definefontfallback [whatever] [Mono] [latinextendeda] [force=yes] % 0x0100:0x017F +% \definefontfallback [whatever] [Mono] [latin extended a] [force=yes] % 0x0100:0x017F +% +% \definefontsynonym[SerifPlus][Serif][fallbacks=whatever] +% +% \definefont[MySerif][SerifPlus at 10pt] +% +% \startcolumns[n=6] +% \MySerif +% \dostepwiserecurse {0} {65000} {1} { +% \iffontchar\font\recurselevel +% {\tttf\uchexnumbers\recurselevel:} \char\recurselevel\par +% \fi +% } +% \stopcolumns + +% \definefontfeature[zh][mode=node,script=hang,lang=zhs] +% \definefontfallback[serifwhatever] [lmroman10-regular] [0x0000-0x0400][force=yes] +% \definefontfallback[serifboldwhatever] [lmroman10-bold] [0x0000-0x0400][force=yes] +% \definefontfallback[serifitalicwhatever] [lmroman10-italic] [0x0000-0x0400][force=yes] +% \definefontfallback[serifbolditalicwhatever][lmroman10-bolditalic][0x0000-0x0400][force=yes] +% +% \starttypescript [serif] [zhfont] +% \definefontsynonym [zhserif] [AdobeSongStd-Light] [features=zh,fallbacks=serifwhatever] +% \definefontsynonym [zhserifbold] [AdobeHeitiStd-Regular][features=zh,fallbacks=serifboldwhatever] +% \definefontsynonym [zhserifitalic] [AdobeKaitiStd-Regular][features=zh,fallbacks=serifitalicwhatever] +% \definefontsynonym [zhserifbolditalic][AdobeHeitiStd-Regular][features=zh,fallbacks=serifbolditalicwhatever] +% \stoptypescript +% +% \starttypescript [serif][zhfont][name] +% \definefontsynonym[Serif] [zhserif] % [fallbacks=serifwhatever] +% \definefontsynonym[SerifBold] [zhserifbold] % [fallbacks=serifboldwhatever] +% \definefontsynonym[SerifItalic] [zhserifitalic] % [fallbacks=serifitalicwhatever] +% \definefontsynonym[SerifBoldItalic] [zhserifbolditalic] % [fallbacks=serifbolditalicwhatever] +% \stoptypescript +% +% \starttypescript[myfont] +% \definetypeface[myfont][rm][serif][zhfont] +% \stoptypescript +% +% \usetypescript[myfont] \setupbodyfont[myfont,rm,12pt] +% +% \starttext +% fonts {\bf fonts} {\bi fonts} {\it fonts} +% \stoptext + +\protect \endinput diff --git a/tex/context/base/font-col.tex b/tex/context/base/font-col.tex deleted file mode 100644 index 3383b6515..000000000 --- a/tex/context/base/font-col.tex +++ /dev/null @@ -1,148 +0,0 @@ -%D \module -%D [ file=font-col, -%D version=2008.06.11, -%D title=\CONTEXT\ Font Macros, -%D subtitle=Fallbacks (collections), -%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. - -% ! EXPERIMENTAL ! code will be made more nice - -% todo: missing only, force always, multiple fallbacks with test, scale -% -% \resetfontfallback [whatever] -% -% \definefontfallback [whatever] [Slanted] [0x0060-0x007F] [force=yes] -% \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)} - -\registerctxluafile{font-col}{1.001} - -\unprotect - -\def\definefontfallback - {\doquadrupleempty\dodefinefontfallback} - -\def\dodefinefontfallback[#1][#2][#3][#4]% - {\ctxlua{fonts.collections.define("#1","#2",\!!bs#3\!!es,\!!bs#4\!!es)}} - -\def\resetfontfallback - {\dodoubleempty\doresetfontfallback} - -\def\doresetfontfallback[#1][#2]% - {\ctxlua{fonts.collections.reset("#1","#2")}} - -% add fallbacks to last font - -\def\dodefinefontfallbacks#1% - {\ctxlua{fonts.collections.prepare("#1")}} - -% we might as well move the handling to lua but then we need to pass the -% fallbacks, skewchar etc. - -\setfalse\doingfontfallbacks - -\def\dodefinefontfallbacksindeed#1% - {\begingroup - \settrue\doingfontfallbacks - \lastrawfontcall % sets current font id - \dodefinefontfallbacks#1% - \endgroup} - -\appendtoks - \ifconditional\doingfontfallbacks\else - \ifx\@@fontfallbacks\empty - \ifx\@@fontclassfallbacks\empty - \else - \dodefinefontfallbacksindeed\@@fontclassfallbacks - \fi - \else - \dodefinefontfallbacksindeed\@@fontfallbacks - \fi - \fi -\to\everydefinefont - -\def\dostartcloningfonts - {\bgroup - \let\savedfontspec\somefontspec} - -\def\dostopcloningfonts - {\egroup} - -\def\doclonefonta#1#2% kind of dododefinefont - {\ctxlua{fonts.collections.message("defining #1 (relative scale: #2)")}% - \autofontsizefalse - \let\lastfontidentifier\s!dummy - \def\localrelativefontsize{#2}% - \let\localabsolutefontsize\fontbody - \lowleveldefinefont{#1}\rawfontidentifier - \csname\rawfontidentifier\endcsname - \autofontsizefalse - %\setfontcharacteristics - }%\the\everyfontswitch} - -\def\doclonefontb#1% #2 - {\doclonefonta{#1 \savedfontspec}} - -% check : only replace when present in replacement font (default: no) -% force : force replacent even when basefont has glyph (default: yes) - -% \definefontfallback [whatever] [Slanted] [0x0060-0x007F] [force=yes] -% \definefontfallback [whatever] [Bold] [0x0080:0x00FF,0x00A0:0x00AF] [rscale=2.0] -% \definefontfallback [whatever] [BoldSlanted] ["00C0-"00C7] [check=yes,force=yes] -% \definefontfallback [whatever] [Mono] [latinextendeda] [force=yes] % 0x0100:0x017F -% \definefontfallback [whatever] [Mono] [latin extended a] [force=yes] % 0x0100:0x017F -% -% \definefontsynonym[SerifPlus][Serif][fallbacks=whatever] -% -% \definefont[MySerif][SerifPlus at 10pt] -% -% \startcolumns[n=6] -% \MySerif -% \dostepwiserecurse {0} {65000} {1} { -% \iffontchar\font\recurselevel -% {\tttf\uchexnumbers\recurselevel:} \char\recurselevel\par -% \fi -% } -% \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] -% \definefontfallback[serifitalicwhatever] [lmroman10-italic] [0x0000-0x0400][force=yes] -% \definefontfallback[serifbolditalicwhatever][lmroman10-bolditalic][0x0000-0x0400][force=yes] -% -% \starttypescript [serif] [zhfont] -% \definefontsynonym [zhserif] [AdobeSongStd-Light] [features=zh,fallbacks=serifwhatever] -% \definefontsynonym [zhserifbold] [AdobeHeitiStd-Regular][features=zh,fallbacks=serifboldwhatever] -% \definefontsynonym [zhserifitalic] [AdobeKaitiStd-Regular][features=zh,fallbacks=serifitalicwhatever] -% \definefontsynonym [zhserifbolditalic][AdobeHeitiStd-Regular][features=zh,fallbacks=serifbolditalicwhatever] -% \stoptypescript -% -% \starttypescript [serif][zhfont][name] -% \definefontsynonym[Serif] [zhserif] % [fallbacks=serifwhatever] -% \definefontsynonym[SerifBold] [zhserifbold] % [fallbacks=serifboldwhatever] -% \definefontsynonym[SerifItalic] [zhserifitalic] % [fallbacks=serifitalicwhatever] -% \definefontsynonym[SerifBoldItalic] [zhserifbolditalic] % [fallbacks=serifbolditalicwhatever] -% \stoptypescript -% -% \starttypescript[myfont] -% \definetypeface[myfont][rm][serif][zhfont] -% \stoptypescript -% -% \usetypescript[myfont] \setupbodyfont[myfont,rm,12pt] -% -% \starttext -% fonts {\bf fonts} {\bi fonts} {\it fonts} -% \stoptext - -\protect \endinput 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-- +

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:

+situations:

+ + +name:xetex like specs +name@virtual font spec +name*context specification + +--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--

Here we deal with defining fonts. We do so by intercepting the @@ -18,43 +22,30 @@ default loader that only handles .

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-- -

Choosing a font by name and specififying its size is only part of the -game. In order to prevent complex commands, 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.

- -

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.

- --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--

We hardly gain anything when we cache the final (pre scaled) table. But it can be handy for debugging.

@@ -84,7 +75,7 @@ and prepares a table that will move along as we proceed.

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--

A unique hash value is generated by:

--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--

We can resolve the filename using the next function:

--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.

--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.

--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-- -

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:

-situations:

- - -name:xetex like specs -name@virtual font spec -name*context specification - - -

Of course one can always define more.

---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--

We need to check for default features. For this we provide a helper function.

--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.

--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

We overload both the and readers.

--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--

Because encodings are going to disappear, we don't bother defining them in tables. But we may do so some day, for consistency.

@@ -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.

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-- +

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.

+--ldx]]-- + +fonts.triggers = fonts.triggers or { } +fonts.initializers = fonts.initializers or { } +fonts.initializers.common = fonts.initializers.common or { } + +local initializers = fonts.initializers + +--[[ldx-- +

This feature will remove inter-digit kerns.

+--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-- +

This feature will give all glyphs an equal height and/or depth. Valid +values are none, height, depth and +both.

+--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-- +

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 files.

+--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--

This is very experimental code!

--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'] = {

Not much is happening here.

--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 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 {fontclass, defaultfontclass} %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 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 \macros +%D {textonly} +%D +%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\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} -%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\getglobalfontparameters - {\expandafter\dogetglobalfontparameter\@@fontdata,]=,} +\def\dododefinefontsynonymnop[#1]% + {\let\@@ff@@features \undefined + \let\@@ff@@fallbacks\undefined + \expandafter\dogetfontparameternop#1,]=,} -\def\dogetfontparameter#1=#2,% - {\if]#1\else - \expandafter\def\csname\??ff\@@fontfile#1\endcsname{#2}% - \expandafter\dogetfontparameter +\def\dododefinefontsynonymyes[#1]% + {\let\@@ff@@features \undefined + \let\@@ff@@fallbacks\undefined + \expandafter\dogetfontparameteryes#1,]=,} + +\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,46 +1065,13 @@ %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 @@ -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\dododocommand########1{\checkbodyfont{########1}{####1}{##1}}% + \processcommacommand[\fontstylelist]\dododocommand}% + \processcommacommand[\fontalternativelist]\dodocommand}% + \processcommacommand[\fontsizelist]\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} - -\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 @@ -2320,29 +1867,7 @@ \let\fontalternative = \defaultfontalternative \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}} +\let\fontsize = \defaultfontsize %D When \type {\loadfontfileoncetrue}, such files are %D only loaded once! This permits redundant loading, but at @@ -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. +%D In good old \TEX, the old style numerals were often taken +%D from the math fonts. No longer. -% older -% -% \definefont [os] [OldStyle sa *] -% \definefont [frak] [Fraktur sa *] -% \definefont [goth] [Gothic sa *] -% \definefont [cal] [Calligraphic sa *] -% \definefont [bbd] [Blackboard sa *] -% -% newer - -\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] @@ -4294,42 +3670,12 @@ \definealternativestyle [\v!smallcaps] [\sc] [\sc] \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 - \fi} -\def\dogetfontparameternop#1=#2,% - {\if]#1% - \dodododefinefontsynonymnop - \else - \expandafter\def\csname @@ff@@#1\endcsname{#2}% - \expandafter\dogetfontparameternop +\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\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\definestyleinstance + {\doquadrupleargument\dodefinestyleinstance} -\def\updatefontparametersyes - {\@@thefeaturesyes \somefontname - \@@thefallbacksyes\somefontname - \@@theskewcharyes \somefontname} -\def\updatefontparametersnop - {\@@thefeaturesnop \somefontname - \@@thefallbacksnop\somefontname - \@@theskewcharnop \somefontname} - -\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-- +

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.

+--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--

Eventually this code will disappear because map files are kind of obsolete. Some code may move to runtime or auxiliary modules.

@@ -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-- -

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.

+

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.

+ + +we loop over all lookups +for each lookup we do a run over the list of glyphs +but we only process them for features that are enabled +if we're dealing with a contextual lookup, we loop over all contexts +in that loop we quit at a match and then process the list of sublookups +we always continue after the match + + +

In we do this for each font that is used in a list, so in +practice we have quite some nested loops.

+ +

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).

+ +

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.

+--ldx]]-- -

As with the code, we may decide to store more information -in the table.

+fonts = fonts or { } +fonts.otf = fonts.otf or { } +fonts.tfm = fonts.tfm or { } -

Incrementing the version number will force a re-cache. We jump the -number by one when there's a fix in the library or - code that results in different tables.

---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--

We start with a lot of tables and related functions.

--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.global_fields = table.tohash { + "lookups", + "glyphs", + "subfonts", + "luatex", + "pfminfo", + "cidinfo", + "tables", + "names", + "unicodes", + "names", + "anchor_classes", + "kern_classes", + "gpos", + "gsub" } -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.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-- +

Here we go.

+--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-- -

Here we go.

---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) +otf.enhancers["cleanup aat"] = function(data,filename) + if otf.cleanup_aat then 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 - } +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,91 +771,239 @@ 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 - logs.report("load otf","problems with unicode %s of kern %s at glyph %s",vc,k,index) - else - local mkl = mykerns[vl] - if not mkl then - mkl = { } - mykerns[v.lookup] = mkl +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 - if type(uvc) == "table" then - for u=1,#uvc do - mkl[uvc[u]] = vo - end - else - mkl[uvc] = vo + 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 - glyph.mykerns = mykerns - glyph.kerns = nil -- saves space and time - mkdone = true end end - if mkdone then - logs.report("load otf", "replacing 'kerns' tables by 'mykerns' tables") + 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 - 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 + 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) - 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 + +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 -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["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-- +

This module is a bit more split up that I'd like but since we also want to test +with plain it has to be so. This module is part of +and discussion about improvements and functionality mostly happens on the + mailing list.

+ +

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.

+ +

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.

+ +

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 users ask for it.

+ +

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.

+ +

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 + 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 has to include +then in the output eventually.

+ +

The raw table as it coms from gets reorganized in to fit out needs. +In 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).

+ +

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.

+ +

As with the code, we may decide to store more information in the + table.

+ +

Incrementing the version number will force a re-cache. We jump the number by one +when there's a fix in the library or code that +results in different tables.

+--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 "" + 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-- +

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.

+--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-- +

I will implement multiple chain replacements once I run into a font that uses +it. It's not that complex to handle.

+--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-- +

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:

+ + +xxxabcdexxx [single a->A][multiple b->BCD][ligature cde->E] xxxABCDExxx + + +

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.

+--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-- +

Here we replace start by a single variant, First we delete the rest of the +match.

+--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-- +

Here we replace start by a sequence of new glyphs. First we delete the rest of +the match.

+--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-- +

Here we replace start by new glyph. First we delete the rest of the match.

+--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-- +

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).

+--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--

This module implements a name to filename resolver. Names are resolved using a table that has keys filtered from the font related files.

--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--

It would make sense to implement the filters in the related modules, but to keep the overview, we define them here.

--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.

--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).

--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-- -

A handy helper.

---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--

Fallbacks, not permanent but a transition thing.

--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--

Here we only implement a few helper functions.

--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--

The next function encapsulates the standard loader as supplied by .

--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 uses a negative multiple of 1000 as a signal for a font scaled based on the design size.

--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.)

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 @@ -348,235 +593,6 @@ function tfm.scale(tfmtable, scaledpoints) return t end ---[[ldx-- -

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.

---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-- -

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.

---ldx]]-- - -fonts.initializers = fonts.initializers or { } -fonts.initializers.common = fonts.initializers.common or { } - ---[[ldx-- -

This feature will remove inter-digit kerns.

---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-- -

This feature will give all glyphs an equal height and/or depth. Valid -values are none, height, depth and -both.

---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-- -

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 files.

---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--

Analyzers run per script and/or language and are needed in order to process features right.

@@ -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-- -

We move marks into the components list. This saves much nasty testing later on.

---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.mkii b/tex/context/base/font-uni.mkii new file mode 100644 index 000000000..1b8ce8e43 --- /dev/null +++ b/tex/context/base/font-uni.mkii @@ -0,0 +1,444 @@ +%D \module +%D [ file=font-uni, +%D version=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 \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 +%D that some mixture of one and two byte encoding was used, +%D which he confirmed. Since \TEX\ normally does not use the +%D characters $>127$, so as long as the two byte characters +%D have a first character with code $>127$, we can use active +%D characters to handle them. In an optimistic mood, I called +%D this module the \UNICODE\ font module. In the module that +%D handles Chinese, we will see that some more interpretation +%D is involved, which is why the macros handling those +%D characters look ahead. + +\unprotect + +%D \macros +%D {handleunicodeflowglyph, uchar, +%D handleunicodeglyph, insertunicodeglyph, +%D unicodeposition, unicodeone, unicodetwo} +%D +%D For the moment \UNICODE\ support is rather primitive but +%D nevertheless effective. The reference to \UNICODE\ is not +%D entirely correct, since in many cases one will use \quote +%D {older} mappings, but in principle, \UNICODE\ can be +%D supported. +%D +%D We expect each character to come as two eight bit +%D characters. Those doubles are handled by making all +%D characters in the range $>127$ active, so that they can +%D pick up the next one, and act upon both their values. +%D Internally only numbers are used. A first implementation +%D simply internally prefixed the second part of the \UNICODE\ +%D pair with \type {\string} or \type {\char}, but this was +%D not that handy when it came to testing those values. +%D Because in principle we are dealing with an encoding, the +%D making active is handled in \type {enco-uni}. +%D +%D There are two commands to handle unicode characters: +%D +%D \starttyping +%D \handleunicodeflowglyph{number}{character} +%D \uchar{number}{number} +%D \stoptyping +%D +%D The first one can be assigned to an active character, the +%D second one can be used to directly access a glyph. Both +%D command call \type {\handleunicodeglyph} that in turn +%D calls \type {\insertunicodeglyph}. Both can be overruled +%D in specialized modules. The low level command \type +%D {\unicodeglyph} can best be left untouched, which is not +%D so much a problem because there is a hook into this macro: +%D \type {\unicodecharcommand}. +%D +%D In most cases one will redefine \type {\handleunicodeglyph} +%D in such a way that it identifies special situations first, +%D takes some actions next, calls \type {\insertunicodeglyph}, +%D if needed with \type {\unicodecharcommand} changed, and +%D finally does some finishing: +%D +%D \starttyping +%D \def\handleunicodeglyph +%D {take actions based on \unicodeone-two-position cq. \nextutoken +%D redefine \unicodecharcommand if needed +%D expand \insertunicodeglyph +%D take some final actions} +%D \stoptyping + +\newcount\unicodeposition + +%D The multistep approach is needed to pick up the second +%D token, since this token can have any value and any +%D catcode. + +% the \relax trick prevents eating up the space (needed for +% korean + +\def\handleunicodeflowglyph#1#2% + {\begingroup + \edef\unicodeone{#1}% + \@EA\afterassignment\@EA\dohandleunicodeflowglyph % two redundant ea's + \@EA\chardef\@EA\nexttoken\@EA`\string#2\relax} + +\def\dohandleunicodeflowglyph\relax + {\futurelet\nextutoken\dodohandleunicodeflowglyph} + +\def\dodohandleunicodeflowglyph % todo tex (or maybe no longer) + {\edef\unicodetwo{\the\nexttoken}% + \unicodeposition\numexpr\unicodeone*256+\unicodetwo\relax + \handleunicodeglyph + \endgroup} + +\unexpanded\def\uchar#1#2% use as standalone glyph + {\begingroup + \edef\unicodeone{#1}% + \edef\unicodetwo{#2}% + \unicodeposition\numexpr\unicodeone*256+\unicodetwo\relax + \handleunicodeglyph + \endgroup} + +\let\nextutoken\relax + +\unexpanded\def\lookaheaduchar#1#2% + {\def\dolookaheaduchar{\uchar{#1}{#2}\let\nextutoken\relax}% + \futurelet\nextutoken\dolookaheaduchar} + +\def\dohandleucflowglyph + {\unicodeposition\numexpr\unicodeone*256+\unicodetwo\relax + \handleunicodeglyph + \endgroup} + +\unexpanded\def\uc#1#2% used in tricky situations + {\begingroup + \edef\unicodeone{#1}% + \edef\unicodetwo{#2}% + \futurelet\nextutoken\dohandleucflowglyph} + +\def\insertunicodeglyph + {\unicodeglyph\unicodeone\unicodetwo} + +\let\handleunicodeglyph\insertunicodeglyph + +%D One can use the \type {\unicodeposition} in the macros +%D that handle pre and post material. + +%D \macros +%D {unicodestyle, unicodecharcommand} +%D +%D Each character pair will become one glyph. Because \TEX\ +%D cannot handle fonts with more that 256 characters, we use +%D \TFM\ files for each range. The first character of the pair +%D is appended to the name of a font, and the second is used to +%D access the glyph in that font. This means that a particular +%D font is split up in subfonts with names in the range: +%D +%D \starttyping +%D 80 ... ff +%D \stoptyping +%D +%D The \type {} as well as the composed name are +%D mapped ones. The next macros take care of this mapping. +%D Let us assume that the next mapping has taken place, +%D +%D \starttyping +%D \definefontsynonym [UnicodeRegular] [gbsong] +%D \stoptyping +%D +%D Let us also assume that we are dealing with the range \type +%D {b1}. Given that a font name results from: +%D +%D \starttyping +%D \truefontname{\truefontname{UnicodeRegular}b1} +%D \stoptyping +%D +%D we get \type {gbsongb1}. The outer \type {\truefontname} +%D takes care of additional mapping, so when we say: +%D +%D \starttyping +%D \definefontsynonym [gbsongb1] [gbsong-b1] +%D \stoptyping +%D +%D the filename used will be \type {gbsong-b1}. From the next +%D definition it will be clear that other fontshapes are also +%D supported. The prefix \type {Unicode} is mapped! +%D +%D The command \type {\unicodecharcommand} can be used to +%D handle special cases. At that moment \type {1em} is known. + +\def\unicodestyle + {\truefontname\s!Unicode\fontstylesuffix} + +\let\unicodecharcommand\firstofoneargument + +\unexpanded\def\unicodeglyph#1#2% watch the double mapping + {\begingroup + \getvalue{@@\currentucharmapping\strippedcsname\uchar}{#1}{#2}% map to a to hex font range + \bodyfontsize\unicodescale\bodyfontsize + % readable: + % \doifelsefontsynonym{\unicodestyle\unicodeone} + % {\font\unicodefont=\truefontname{\unicodestyle\unicodeone} + % at \currentfontscale\bodyfontsize} + % {\font\unicodefont=\truefontname{\truefontname\unicodestyle\unicodeone} + % at \currentfontscale\bodyfontsize}% + % unreadable but more efficient: + \font\unicodefont=\truefontname{\doifelsefontsynonym{\unicodestyle + \unicodeone}\empty\truefontname\unicodestyle\unicodeone} + at \currentfontscale\bodyfontsize + \unicodestrut % off by default + \unicodefont\unicodecharcommand{\char\unicodetwo\relax}% + \endgroup} + +%D This handler is used by default, for instance in: +%D +%D \starttyping +%D \defineunicodefont [MySwitch] [MyFont] % [strut=no,command=\insertunicodeglyph] +%D +%D \definefontsynonym [MyFontRegular40] [Sans] +%D \definefontsynonym [MyFontBold40] [SansBold] +%D +%D {\MySwitch \uchar{"40}{`a}} +%D {\MySwitch \bf \uchar{"40}{`a}} +%D \stoptyping +%D +%D \starttyping +%D \definefontsynonym [MyFontRegular] [Sans] +%D \definefontsynonym [MyFontBold] [SansBold] +%D \stoptyping +%D +%D Is also possible, but in that case the number is appended to the raw font +%D name! + +%D \macros +%D {currentucharmapping,defineucharmapping} +%D +%D A (plane,char) pair can be remapped using a uchar mapping +%D function. The default mapping is to convert the plane to a +%D lowercase hexadecimal number, and leave the number +%D untouched. The current remapping is kept in a macro. + +\let\currentucharmapping\s!default + +\def\defineucharmapping#1% + {\setvalue{@@#1\strippedcsname\uchar}} + +\defineucharmapping{\s!default}#1#2% + {\edef\unicodeone{\lchexnumbers{#1}}\edef\unicodetwo{#2}} + +%D An example of a remapping is the following: +%D +%D \starttyping +%D \defineucharmapping{GBK}#1#2% +%D {\unicodeposition=#1 +%D \advance\unicodeposition -129 +%D \multiply\unicodeposition 190 +%D \advance\unicodeposition #2 +%D \advance\unicodeposition-\ifnum#2>127 65\else64\fi +%D \dorepositionunicode} +%D \stoptyping +%D +%D This maps the GBK vector onto a compact GBK one. The +%D auxiliary macro is defined here as a goody. + +\def\dorepositionunicode + {\dosetdivision\unicodeposition{256}\scratchcounter + \advance\scratchcounter \plusone + \edef\unicodeone{\ifnum\scratchcounter<10 0\fi\the\scratchcounter}% + \dosetmodulo\unicodeposition{256}\scratchcounter + \edef\unicodetwo{\the\scratchcounter}} + +%D \macros +%D {setunicodestrut, setunicodescale, nextutoken, +%D handleunicodeglyph, insertunicodeglyph} +%D +%D A careful analysis of the previous macros, learns that the +%D process of mapping comes down to: +%D +%D \startitemize[packed,n] +%D \item taking care of preceding material (and spacing) +%D \item defining the font at \type {\currentfontscale} $\times$ +%D \type {\unicodescale} $\times$ \type {\bodyfontsize} +%D \item inserting a \type {\unicodestrut} +%D \item inserting the character (glyph) +%D \item executing some actions afterwards +%D \stopitemize +%D +%D The actions before and after placing the glyph, is up to +%D the user supplied handler. This handler (\type +%D {\handleunicodeglpyh}) must, at a certain moment, insert +%D the glyph using \type {\insertunicodeglyph} + +\def\setunicodescale#1% + {\def\unicodescale{#1}} + +\def\dosetunicodestrut#1#2% height depth + {\def\unicodestrut + {\vrule + \!!width \zeropoint + \!!height#1\strutht + \!!depth #2\strutdp + \relax}} + +\def\setunicodestrut#1#2% height depth + {\ifdim#1\strutht>\zeropoint + \dosetunicodestrut{#1}{#2}% + \else\ifdim#1\strutdp>\zeropoint + \dosetunicodestrut{#1}{#2}% + \else + \let\unicodestrut\empty + \fi\fi} + +\def\resetunicodestrut + {\let\unicodestrut\empty} + +%D The additional scaling and strut default to: + +\setunicodescale{1} +\setunicodestrut{1}{1} + +%D But better is not to have a strut added by default: + +\resetunicodestrut + +%D The actual code for the additional actions as well as +%D specific spacing is handled outside these routines. The +%D character after the two that are under treatment is +%D available in \type {\nextutoken}. + +%D \macros +%D {defineunicodefont, setupunicodefont} +%D +%D Apart from this rather low level implementation, we also +%D provide a more user friendly alternative. Given that one +%D has defined: +%D +%D \starttyping +%D \defineunicodefont +%D [SimChi] [SimplifiedChinese] +%D [\c!scale=0.85, +%D \c!height=1.25, +%D \c!depth=1.00, +%D \c!interlinespaceinterlinie=yes, +%D \c!conversion=\chinesenumber, +%D \c!command=\handlechineseunicodeglyph] +%D \stoptyping +%D +%D Together with: +%D +%D \starttyping +%D \definefontsynonym [SimplifiedChineseRegular] [gbsong] +%D \definefontsynonym [SimplifiedChineseSlanted] [gbsongsl] +%D \stoptyping +%D +%D we can now switch to Simplified Chinese by saying \type +%D {SimChi}. Some values can be changed afterwards with +%D +%D \starttyping +%D \setupunicodefont[SimChi][...=...] +%D \stoptyping +%D +%D Specific initializations can be assigned to \type +%D {commands}. + +\def\defineunicodefont + {\dotripleempty\dodefineunicodefont} + +\def\dodefineunicodefont[#1][#2][#3]% + {\doifassignmentelse{#3} + {\setupunicodefont[#1][#3]} + {\doifelsenothing{#3} + {\setupunicodefont[#1][#3]} + {\copyparameters + [\??uc#1][\??uc#3] + [\c!height,\c!depth,\c!scale,\c!commands,\c!strut, + \c!interlinespace,\c!command,\c!conversion]}}% + \doifelsenothing{#2} + {\setvalue{#1}{[uc font #1 undefined]}} + {\setvalue{\??uc#1\c!file}{#2}% + \doifundefined{\??ff#2\s!Bold} + {\definefontsynonym[#2\s!Bold] [#2\s!Regular]% + \definefontsynonym[#2\s!Slanted] [#2\s!Regular]% + \definefontsynonym[#2\s!Italic] [#2\s!Regular]% + \definefontsynonym[#2\s!BoldSlanted][#2\s!Slanted]% + \definefontsynonym[#2\s!BoldItalic] [#2\s!Italic]}% + \unexpanded\setvalue{#1}{\enableunicodefont{#1}}}} + +\def\setupunicodefont + {\dodoubleempty\dosetupunicodefont} + +\def\dosetupunicodefont[#1][#2]% also predefines + {\doifundefined{\??uc#1\c!command} + {\copyparameters + [\??uc#1][\??uc\s!default] + [\c!height,\c!depth,\c!scale,\c!commands,\v!strut, + \c!interlinespace,\c!command,\c!conversion]}% + \getparameters[\??uc#1][#2]} + +\def\enableunicodefont#1% + {\definefontsynonym[\s!Unicode][\getvalue{\??uc#1\c!file}]% + \def\unicodescale {\getvalue{\??uc#1\c!scale}}% + \def\unicodeheight {\getvalue{\??uc#1\c!height}}% + \def\unicodedepth {\getvalue{\??uc#1\c!depth}}% + \def\unicodedigits {\getvalue{\??uc#1\c!conversion}}% + \def\handleunicodeglyph {\getvalue{\??uc#1\c!command}}% + \doifnot\currentregime{utf}{\enableregime[unicode]}% + % the following \relax's are realy needed + \doifvalue{\??uc#1\c!interlinespace}\v!yes + \setupinterlinespace\relax + \doifelsevalue{\??uc#1\c!strut}\v!yes + {\setunicodestrut\unicodeheight\unicodedepth} + {\resetunicodestrut}% + \getvalue{\??uc#1\c!commands}\relax} + +%D \macros +%D {unicodedigits} +%D +%D For convenience we also predefine a number conversion +%D macro: + +\let\unicodedigits\number + +%D Because we cannot be sure of the pressence of all font +%D styles, we remap some by default. + +\definefontsynonym [\s!Unicode\s!Bold] [\s!Unicode\s!Regular] +\definefontsynonym [\s!Unicode\s!Slanted] [\s!Unicode\s!Regular] +\definefontsynonym [\s!Unicode\s!Italic] [\s!Unicode\s!Regular] +\definefontsynonym [\s!Unicode\s!BoldSlanted] [\s!Unicode\s!Slanted] +\definefontsynonym [\s!Unicode\s!BoldItalic] [\s!Unicode\s!Italic] + +\setupunicodefont + [\s!default] + [\c!height=1, + \c!depth=1, + \c!scale=1, + \c!strut=\v!no, + \c!interlinespace=\v!no, + \c!command=\insertunicodeglyph, + \c!conversion=\number] + +\protect \endinput 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-uni.tex b/tex/context/base/font-uni.tex deleted file mode 100644 index 7d4f3e442..000000000 --- a/tex/context/base/font-uni.tex +++ /dev/null @@ -1,465 +0,0 @@ -%D \module -%D [ file=font-uni, -%D version=1999.10.10, -%D title=\CONTEXT\ Font Macros, -%D subtitle=\UNICODE\ 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 Font Macros / UNICODE Support} - -%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 -%D that some mixture of one and two byte encoding was used, -%D which he confirmed. Since \TEX\ normally does not use the -%D characters $>127$, so as long as the two byte characters -%D have a first character with code $>127$, we can use active -%D characters to handle them. In an optimistic mood, I called -%D this module the \UNICODE\ font module. In the module that -%D handles Chinese, we will see that some more interpretation -%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 -%D {handleunicodeflowglyph, uchar, -%D handleunicodeglyph, insertunicodeglyph, -%D unicodeposition, unicodeone, unicodetwo} -%D -%D For the moment \UNICODE\ support is rather primitive but -%D nevertheless effective. The reference to \UNICODE\ is not -%D entirely correct, since in many cases one will use \quote -%D {older} mappings, but in principle, \UNICODE\ can be -%D supported. -%D -%D We expect each character to come as two eight bit -%D characters. Those doubles are handled by making all -%D characters in the range $>127$ active, so that they can -%D pick up the next one, and act upon both their values. -%D Internally only numbers are used. A first implementation -%D simply internally prefixed the second part of the \UNICODE\ -%D pair with \type {\string} or \type {\char}, but this was -%D not that handy when it came to testing those values. -%D Because in principle we are dealing with an encoding, the -%D making active is handled in \type {enco-uni}. -%D -%D There are two commands to handle unicode characters: -%D -%D \starttyping -%D \handleunicodeflowglyph{number}{character} -%D \uchar{number}{number} -%D \stoptyping -%D -%D The first one can be assigned to an active character, the -%D second one can be used to directly access a glyph. Both -%D command call \type {\handleunicodeglyph} that in turn -%D calls \type {\insertunicodeglyph}. Both can be overruled -%D in specialized modules. The low level command \type -%D {\unicodeglyph} can best be left untouched, which is not -%D so much a problem because there is a hook into this macro: -%D \type {\unicodecharcommand}. -%D -%D In most cases one will redefine \type {\handleunicodeglyph} -%D in such a way that it identifies special situations first, -%D takes some actions next, calls \type {\insertunicodeglyph}, -%D if needed with \type {\unicodecharcommand} changed, and -%D finally does some finishing: -%D -%D \starttyping -%D \def\handleunicodeglyph -%D {take actions based on \unicodeone-two-position cq. \nextutoken -%D redefine \unicodecharcommand if needed -%D expand \insertunicodeglyph -%D take some final actions} -%D \stoptyping - -\newcount\unicodeposition - -%D The multistep approach is needed to pick up the second -%D token, since this token can have any value and any -%D catcode. - -% the \relax trick prevents eating up the space (needed for -% korean - -\def\handleunicodeflowglyph#1#2% - {\begingroup - \edef\unicodeone{#1}% - \@EA\afterassignment\@EA\dohandleunicodeflowglyph % two redundant ea's - \@EA\chardef\@EA\nexttoken\@EA`\string#2\relax} - -\def\dohandleunicodeflowglyph\relax - {\futurelet\nextutoken\dodohandleunicodeflowglyph} - -\def\dodohandleunicodeflowglyph % todo tex (or maybe no longer) - {\edef\unicodetwo{\the\nexttoken}% - \unicodeposition\numexpr\unicodeone*256+\unicodetwo\relax - \handleunicodeglyph - \endgroup} - -\unexpanded\def\uchar#1#2% use as standalone glyph - {\begingroup - \edef\unicodeone{#1}% - \edef\unicodetwo{#2}% - \unicodeposition\numexpr\unicodeone*256+\unicodetwo\relax - \handleunicodeglyph - \endgroup} - -\let\nextutoken\relax - -\unexpanded\def\lookaheaduchar#1#2% - {\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 - \endgroup} - -\unexpanded\def\uc#1#2% used in tricky situations - {\begingroup - \edef\unicodeone{#1}% - \edef\unicodetwo{#2}% - \futurelet\nextutoken\dohandleucflowglyph} - -\def\insertunicodeglyph - {\unicodeglyph\unicodeone\unicodetwo} - -\let\handleunicodeglyph\insertunicodeglyph - -%D One can use the \type {\unicodeposition} in the macros -%D that handle pre and post material. - -%D \macros -%D {unicodestyle, unicodecharcommand} -%D -%D Each character pair will become one glyph. Because \TEX\ -%D cannot handle fonts with more that 256 characters, we use -%D \TFM\ files for each range. The first character of the pair -%D is appended to the name of a font, and the second is used to -%D access the glyph in that font. This means that a particular -%D font is split up in subfonts with names in the range: -%D -%D \starttyping -%D 80 ... ff -%D \stoptyping -%D -%D The \type {} as well as the composed name are -%D mapped ones. The next macros take care of this mapping. -%D Let us assume that the next mapping has taken place, -%D -%D \starttyping -%D \definefontsynonym [UnicodeRegular] [gbsong] -%D \stoptyping -%D -%D Let us also assume that we are dealing with the range \type -%D {b1}. Given that a font name results from: -%D -%D \starttyping -%D \truefontname{\truefontname{UnicodeRegular}b1} -%D \stoptyping -%D -%D we get \type {gbsongb1}. The outer \type {\truefontname} -%D takes care of additional mapping, so when we say: -%D -%D \starttyping -%D \definefontsynonym [gbsongb1] [gbsong-b1] -%D \stoptyping -%D -%D the filename used will be \type {gbsong-b1}. From the next -%D definition it will be clear that other fontshapes are also -%D supported. The prefix \type {Unicode} is mapped! -%D -%D The command \type {\unicodecharcommand} can be used to -%D handle special cases. At that moment \type {1em} is known. - -\def\unicodestyle - {\truefontname\s!Unicode\fontstylesuffix} - -\let\unicodecharcommand\firstofoneargument - -\unexpanded\def\unicodeglyph#1#2% watch the double mapping - {\begingroup - \getvalue{@@\currentucharmapping\strippedcsname\uchar}{#1}{#2}% map to a to hex font range - \bodyfontsize\unicodescale\bodyfontsize - % readable: - % \doifelsefontsynonym{\unicodestyle\unicodeone} - % {\font\unicodefont=\truefontname{\unicodestyle\unicodeone} - % at \currentfontscale\bodyfontsize} - % {\font\unicodefont=\truefontname{\truefontname\unicodestyle\unicodeone} - % at \currentfontscale\bodyfontsize}% - % unreadable but more efficient: - \font\unicodefont=\truefontname{\doifelsefontsynonym{\unicodestyle - \unicodeone}\empty\truefontname\unicodestyle\unicodeone} - at \currentfontscale\bodyfontsize - \unicodestrut % off by default - \unicodefont\unicodecharcommand{\char\unicodetwo\relax}% - \endgroup} - -%D This handler is used by default, for instance in: -%D -%D \starttyping -%D \defineunicodefont [MySwitch] [MyFont] % [strut=no,command=\insertunicodeglyph] -%D -%D \definefontsynonym [MyFontRegular40] [Sans] -%D \definefontsynonym [MyFontBold40] [SansBold] -%D -%D {\MySwitch \uchar{"40}{`a}} -%D {\MySwitch \bf \uchar{"40}{`a}} -%D \stoptyping -%D -%D \starttyping -%D \definefontsynonym [MyFontRegular] [Sans] -%D \definefontsynonym [MyFontBold] [SansBold] -%D \stoptyping -%D -%D Is also possible, but in that case the number is appended to the raw font -%D name! - -%D \macros -%D {currentucharmapping,defineucharmapping} -%D -%D A (plane,char) pair can be remapped using a uchar mapping -%D function. The default mapping is to convert the plane to a -%D lowercase hexadecimal number, and leave the number -%D untouched. The current remapping is kept in a macro. - -\let\currentucharmapping\s!default - -\def\defineucharmapping#1% - {\setvalue{@@#1\strippedcsname\uchar}} - -\defineucharmapping{\s!default}#1#2% - {\edef\unicodeone{\lchexnumbers{#1}}\edef\unicodetwo{#2}} - -%D An example of a remapping is the following: -%D -%D \starttyping -%D \defineucharmapping{GBK}#1#2% -%D {\unicodeposition=#1 -%D \advance\unicodeposition -129 -%D \multiply\unicodeposition 190 -%D \advance\unicodeposition #2 -%D \advance\unicodeposition-\ifnum#2>127 65\else64\fi -%D \dorepositionunicode} -%D \stoptyping -%D -%D This maps the GBK vector onto a compact GBK one. The -%D auxiliary macro is defined here as a goody. - -\def\dorepositionunicode - {\dosetdivision\unicodeposition{256}\scratchcounter - \advance\scratchcounter \plusone - \edef\unicodeone{\ifnum\scratchcounter<10 0\fi\the\scratchcounter}% - \dosetmodulo\unicodeposition{256}\scratchcounter - \edef\unicodetwo{\the\scratchcounter}} - -%D \macros -%D {setunicodestrut, setunicodescale, nextutoken, -%D handleunicodeglyph, insertunicodeglyph} -%D -%D A careful analysis of the previous macros, learns that the -%D process of mapping comes down to: -%D -%D \startitemize[packed,n] -%D \item taking care of preceding material (and spacing) -%D \item defining the font at \type {\currentfontscale} $\times$ -%D \type {\unicodescale} $\times$ \type {\bodyfontsize} -%D \item inserting a \type {\unicodestrut} -%D \item inserting the character (glyph) -%D \item executing some actions afterwards -%D \stopitemize -%D -%D The actions before and after placing the glyph, is up to -%D the user supplied handler. This handler (\type -%D {\handleunicodeglpyh}) must, at a certain moment, insert -%D the glyph using \type {\insertunicodeglyph} - -\def\setunicodescale#1% - {\def\unicodescale{#1}} - -\def\dosetunicodestrut#1#2% height depth - {\def\unicodestrut - {\vrule - \!!width \zeropoint - \!!height#1\strutht - \!!depth #2\strutdp - \relax}} - -\def\setunicodestrut#1#2% height depth - {\ifdim#1\strutht>\zeropoint - \dosetunicodestrut{#1}{#2}% - \else\ifdim#1\strutdp>\zeropoint - \dosetunicodestrut{#1}{#2}% - \else - \let\unicodestrut\empty - \fi\fi} - -\def\resetunicodestrut - {\let\unicodestrut\empty} - -%D The additional scaling and strut default to: - -\setunicodescale{1} -\setunicodestrut{1}{1} - -%D But better is not to have a strut added by default: - -\resetunicodestrut - -%D The actual code for the additional actions as well as -%D specific spacing is handled outside these routines. The -%D character after the two that are under treatment is -%D available in \type {\nextutoken}. - -%D \macros -%D {defineunicodefont, setupunicodefont} -%D -%D Apart from this rather low level implementation, we also -%D provide a more user friendly alternative. Given that one -%D has defined: -%D -%D \starttyping -%D \defineunicodefont -%D [SimChi] [SimplifiedChinese] -%D [\c!scale=0.85, -%D \c!height=1.25, -%D \c!depth=1.00, -%D \c!interlinespaceinterlinie=yes, -%D \c!conversion=\chinesenumber, -%D \c!command=\handlechineseunicodeglyph] -%D \stoptyping -%D -%D Together with: -%D -%D \starttyping -%D \definefontsynonym [SimplifiedChineseRegular] [gbsong] -%D \definefontsynonym [SimplifiedChineseSlanted] [gbsongsl] -%D \stoptyping -%D -%D we can now switch to Simplified Chinese by saying \type -%D {SimChi}. Some values can be changed afterwards with -%D -%D \starttyping -%D \setupunicodefont[SimChi][...=...] -%D \stoptyping -%D -%D Specific initializations can be assigned to \type -%D {commands}. - -\def\defineunicodefont - {\dotripleempty\dodefineunicodefont} - -\def\dodefineunicodefont[#1][#2][#3]% - {\doifassignmentelse{#3} - {\setupunicodefont[#1][#3]} - {\doifelsenothing{#3} - {\setupunicodefont[#1][#3]} - {\copyparameters - [\??uc#1][\??uc#3] - [\c!height,\c!depth,\c!scale,\c!commands,\c!strut, - \c!interlinespace,\c!command,\c!conversion]}}% - \doifelsenothing{#2} - {\setvalue{#1}{[uc font #1 undefined]}} - {\setvalue{\??uc#1\c!file}{#2}% - \doifundefined{\??ff#2\s!Bold} - {\definefontsynonym[#2\s!Bold] [#2\s!Regular]% - \definefontsynonym[#2\s!Slanted] [#2\s!Regular]% - \definefontsynonym[#2\s!Italic] [#2\s!Regular]% - \definefontsynonym[#2\s!BoldSlanted][#2\s!Slanted]% - \definefontsynonym[#2\s!BoldItalic] [#2\s!Italic]}% - \unexpanded\setvalue{#1}{\enableunicodefont{#1}}}} - -\def\setupunicodefont - {\dodoubleempty\dosetupunicodefont} - -\def\dosetupunicodefont[#1][#2]% also predefines - {\doifundefined{\??uc#1\c!command} - {\copyparameters - [\??uc#1][\??uc\s!default] - [\c!height,\c!depth,\c!scale,\c!commands,\v!strut, - \c!interlinespace,\c!command,\c!conversion]}% - \getparameters[\??uc#1][#2]} - -\def\enableunicodefont#1% - {\definefontsynonym[\s!Unicode][\getvalue{\??uc#1\c!file}]% - \def\unicodescale {\getvalue{\??uc#1\c!scale}}% - \def\unicodeheight {\getvalue{\??uc#1\c!height}}% - \def\unicodedepth {\getvalue{\??uc#1\c!depth}}% - \def\unicodedigits {\getvalue{\??uc#1\c!conversion}}% - \def\handleunicodeglyph {\getvalue{\??uc#1\c!command}}% - \doifnot\currentregime{utf}{\enableregime[unicode]}% - % the following \relax's are realy needed - \doifvalue{\??uc#1\c!interlinespace}\v!yes - \setupinterlinespace\relax - \doifelsevalue{\??uc#1\c!strut}\v!yes - {\setunicodestrut\unicodeheight\unicodedepth} - {\resetunicodestrut}% - \getvalue{\??uc#1\c!commands}\relax} - -%D \macros -%D {unicodedigits} -%D -%D For convenience we also predefine a number conversion -%D macro: - -\let\unicodedigits\number - -%D Because we cannot be sure of the pressence of all font -%D styles, we remap some by default. - -\definefontsynonym [\s!Unicode\s!Bold] [\s!Unicode\s!Regular] -\definefontsynonym [\s!Unicode\s!Slanted] [\s!Unicode\s!Regular] -\definefontsynonym [\s!Unicode\s!Italic] [\s!Unicode\s!Regular] -\definefontsynonym [\s!Unicode\s!BoldSlanted] [\s!Unicode\s!Slanted] -\definefontsynonym [\s!Unicode\s!BoldItalic] [\s!Unicode\s!Italic] - -\setupunicodefont - [\s!default] - [\c!height=1, - \c!depth=1, - \c!scale=1, - \c!strut=\v!no, - \c!interlinespace=\v!no, - \c!command=\insertunicodeglyph, - \c!conversion=\number] - -\protect \endinput diff --git a/tex/context/base/font-unk.mkii b/tex/context/base/font-unk.mkii new file mode 100644 index 000000000..30f824781 --- /dev/null +++ b/tex/context/base/font-unk.mkii @@ -0,0 +1,187 @@ +%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] +\definefontsynonym [MathExtensionBold] [MathExtension] +\definefontsynonym [MathItalicBold] [MathItalic] +\definefontsynonym [MathSymbolBold] [MathSymbol] +\definefontsynonym [MathAlphaBold] [MathAlpha] +\definefontsynonym [MathBetaBold] [MathBeta] +\definefontsynonym [MathGammaBold] [MathGamma] +\definefontsynonym [MathDeltaBold] [MathDelta] + +\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). + +% \def\setfontsynonym[#1]#2[#3]{\setvalue{\??ff\fontclass#1}{#3}} +% +% \setfontsynonym[\s!Normal] [\fontstringD] +% \setfontsynonym[\s!Bold] [\fontstringD\s!Bold] +% \setfontsynonym[\s!Italic] [\fontstringD\s!Italic] +% \setfontsynonym[\s!Slanted] [\fontstringD\s!Slanted] +% \setfontsynonym[\s!BoldItalic] [\fontstringD\s!BoldItalic] +% \setfontsynonym[\s!BoldSlanted][\fontstringD\s!BoldSlanted] +% \setfontsynonym[\s!Caps] [\fontstringD\s!Caps] + +\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, + ex=MathExtension mo 1, + mi=MathItalic mo 1, + sy=MathSymbol mo 1, + nn=MathNoName mo 1, + ma=MathAlpha mo 1, + mb=MathBeta mo 1, + mc=MathGamma mo 1, + md=MathDelta mo 1] + +\definebodyfont [bfmath] [mm] + [mrbf=MathRomanBold mo 1, + exbf=MathExtensionBold mo 1, + mibf=MathItalicBold mo 1, + sybf=MathSymbolBold mo 1, + mabf=MathAlphaBold mo 1, + mbbf=MathBetaBold mo 1, + mcbf=MathGammaBold mo 1, + mdbf=MathDeltaBold 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-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-unk.tex b/tex/context/base/font-unk.tex deleted file mode 100644 index 4e450ae74..000000000 --- a/tex/context/base/font-unk.tex +++ /dev/null @@ -1,185 +0,0 @@ -%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. - -\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] -\definefontsynonym [MathExtensionBold] [MathExtension] -\definefontsynonym [MathItalicBold] [MathItalic] -\definefontsynonym [MathSymbolBold] [MathSymbol] -\definefontsynonym [MathAlphaBold] [MathAlpha] -\definefontsynonym [MathBetaBold] [MathBeta] -\definefontsynonym [MathGammaBold] [MathGamma] -\definefontsynonym [MathDeltaBold] [MathDelta] - -\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). - -% \def\setfontsynonym[#1]#2[#3]{\setvalue{\??ff\fontclass#1}{#3}} -% -% \setfontsynonym[\s!Normal] [\fontstringD] -% \setfontsynonym[\s!Bold] [\fontstringD\s!Bold] -% \setfontsynonym[\s!Italic] [\fontstringD\s!Italic] -% \setfontsynonym[\s!Slanted] [\fontstringD\s!Slanted] -% \setfontsynonym[\s!BoldItalic] [\fontstringD\s!BoldItalic] -% \setfontsynonym[\s!BoldSlanted][\fontstringD\s!BoldSlanted] -% \setfontsynonym[\s!Caps] [\fontstringD\s!Caps] - -\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, - ex=MathExtension mo 1, - mi=MathItalic mo 1, - sy=MathSymbol mo 1, - nn=MathNoName mo 1, - ma=MathAlpha mo 1, - mb=MathBeta mo 1, - mc=MathGamma mo 1, - md=MathDelta mo 1] - -\definebodyfont [bfmath] [mm] - [mrbf=MathRomanBold mo 1, - exbf=MathExtensionBold mo 1, - mibf=MathItalicBold mo 1, - sybf=MathSymbolBold mo 1, - mabf=MathAlphaBold mo 1, - mbbf=MathBetaBold mo 1, - mcbf=MathGammaBold mo 1, - mdbf=MathDeltaBold 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). - -\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-- +

Choosing a font by name and specififying its size is only part of the +game. In order to prevent complex commands, 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.

+ +

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.

+ +

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.

+--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.mkii b/tex/context/base/java-ini.mkii new file mode 100644 index 000000000..e929da108 --- /dev/null +++ b/tex/context/base/java-ini.mkii @@ -0,0 +1,713 @@ +%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: + +% 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 +%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; j0) && (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} + +\prependtoks \flushJSpreamble \to \everyshipout +\prependtoks \finalflushJSpreamble \to \everylastshipout + +%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}} + +\definespeciallocation{JS}#1#2% + {\iflocation + \bgroup + \bgroup + \presetJScode + \currentreferenceoperation + \currentreferencearguments + \egroup + \dohandlegoto + {#2}% + {\dostartgotoJS\buttonwidth\buttonheight\JScode}% + {\dostopgotoJS}% + \egroup + \else + {#2}% + \fi} + +%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/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; j0) && (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/java-ini.tex b/tex/context/base/java-ini.tex deleted file mode 100644 index 7dc2cfe04..000000000 --- a/tex/context/base/java-ini.tex +++ /dev/null @@ -1,742 +0,0 @@ -%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 - -% 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: - -\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 - - -%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; j0) && (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 - \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} - -\prependtoks \flushJSpreamble \to \everyshipout -\prependtoks \finalflushJSpreamble \to \everylastshipout - -%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}} - -\definespeciallocation{JS}#1#2% - {\iflocation - \bgroup - \bgroup - \presetJScode - \currentreferenceoperation - \currentreferencearguments - \egroup - \dohandlegoto - {#2}% - {\dostartgotoJS\buttonwidth\buttonheight\JScode}% - {\dostopgotoJS}% - \egroup - \else - {#2}% - \fi} - -%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.

--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.

--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--

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.

--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--

The parser used here is inspired by the variant discussed in the lua book, but @@ -38,15 +39,30 @@ optimize the code.

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-- +

This module can be used stand alone but also inside in +which case it hooks into the tracker code. Therefore we provide a few +functions that set the tracers.

+--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--

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("\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.

--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 = { ['&'] = '&', ['<'] = '<', ['>'] = '>', ['"'] = '"' } --~ 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 --~ --~ ]]) ---~ 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.mkii b/tex/context/base/lang-lab.mkii new file mode 100644 index 000000000..269ac249b --- /dev/null +++ b/tex/context/base/lang-lab.mkii @@ -0,0 +1,295 @@ +%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% +% {\ifcsname#2#1#3\endcsname +% \csname#2#1#3\endcsname \else +% \ifcsname#2#3\endcsname +% \csname#2#3\endcsname \else +% \ifcsname#2\defaultlanguage#1#3\endcsname +% \csname#2\defaultlanguage#1#3\endcsname \else +% \ifcsname#2\s!en#3\endcsname +% \csname#2\s!en#3\endcsname \else +% \ifcsname#2\s!nl#3\endcsname +% \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 ! #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 + \reporttextprefixerror{#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-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-lab.tex b/tex/context/base/lang-lab.tex deleted file mode 100644 index 664460129..000000000 --- a/tex/context/base/lang-lab.tex +++ /dev/null @@ -1,284 +0,0 @@ -%D \module -%D [ file=lang-lab, -%D version=1997.08.27, -%D title=\CONTEXT\ Language Macros, -%D subtitle=Language Head and Label Texts, -%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. - -\writestatus{loading}{Language Head and Label Texts} - -\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% -% {\ifcsname#2#1#3\endcsname -% \csname#2#1#3\endcsname \else -% \ifcsname#2#3\endcsname -% \csname#2#3\endcsname \else -% \ifcsname#2\defaultlanguage#1#3\endcsname -% \csname#2\defaultlanguage#1#3\endcsname \else -% \ifcsname#2\s!en#3\endcsname -% \csname#2\s!en#3\endcsname \else -% \ifcsname#2\s!nl#3\endcsname -% \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} - -\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]% don't group! SLOW if really used: speed up - {\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]}}}} - -\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.mkii b/tex/context/base/lang-spe.mkii new file mode 100644 index 000000000..7911b0c95 --- /dev/null +++ b/tex/context/base/lang-spe.mkii @@ -0,0 +1,244 @@ +%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. + +%D This code was originally placed in the language +%D initialization module, but isolating it is clearer. Language +%D specifics evolved out of user demands for special features, +%D like the german active quote. After a while I decided to +%D associate them to languages in a more general way so that we +%D could associate all kind of things with language switching. +%D +%D This is a typical example of functionality that occasionally +%D gets improved based on user input and experience. Much of the +%D code is pretty old and could probabbly be done in better ways. +%D It's probably also the kind of code that has been and will be +%D written over and over again by \TEX\ users around the world, +%D so there are probably better implementations of similar +%D functionality around. Therefore, users are invited to pop in +%D their own handling as long as it does not interfere with +%D existing code. Writing the more obscure macros that deal with +%D this is a good learning experience (catcodes, lccodes, token +%D lists, expansion, \unknown). + +\writestatus{loading}{ConTeXt Language Macros / Specifics} + +\unprotect + +%D \macros +%D {everyresetlanguagespecifics,resetlanguagespecifics} +%D +%D Cleanup macros. + +\newevery \everyresetlanguagespecifics \relax + +\def\resetlanguagespecifics + {\ifcase\protectionlevel + \the\everyresetlanguagespecifics + \else % to be translated + % \writestatus\m!systems{don't change language in unprotected mode!}% + \fi} + +\appendtoks + \resetlanguagespecifics +\to \everycleanupfeatures + +%D \macros +%D {startlanguagespecifics,enablelanguagespecifics} +%D +%D Each language has its own typographic pecularities. Some of +%D those can be influenced by parameters, others are handled by +%D the interface, but as soon as specific commands come into +%D view we need another mechanism. In the macro that activates +%D a language, we call \type{\enablelanguagespecifics}. This +%D macro in return calls for the setup of language specific +%D macros. Such specifics are defined as: +%D +%D \starttyping +%D \startlanguagespecifics[de] +%D \installcompoundcharacter "a {\"a} +%D \installcompoundcharacter "e {\"e} +%D \installcompoundcharacter "s {\SS} +%D \stoplanguagespecifics +%D \stoptyping +%D +%D Instead of \type{[du]} we can pass a comma separated +%D list, like \type{[du,nl]}. Next calls to this macro add the +%D specifics to the current list. +%D +%D Before we actually read the specifics, we first take some +%D precautions that will prevent spurious spaces to creep into +%D the list. + +% We should use token registers, but alas, we run out of them and +% \ETEX\ has a bug. Well, let's use a token register now (2006). + +\def\startlanguagespecifics% % we use double to + {\bgroup + \catcode`\^^I=\@@ignore + \catcode`\^^M=\@@ignore + \catcode`\^^L=\@@ignore + \dodoubleempty\dostartlanguagespecifics} % get rid of spaces + +%D The main macro looks quite complicated but actually does +%D nothing special. By embedding \type{\do} we can easily +%D append to the lists and also execute them at will. Just to +%D be sure, we check on spurious spaces. The second dummy +%D argument gobbles spaces. + +\def\languageencoding + {\ifx\characterencoding\nocharacterencoding \else + \characterencoding-% + \fi} + +\long\def\dostartlanguagespecifics[#1][#2]#3\stoplanguagespecifics + {\egroup + \processcommalist[#1]{\dosetlanguagespecifics{#3}}} + +% \long\def\dosetlanguagespecifics#1#2% +% {\ifundefined{\??la\languageencoding#2\??la}\forgetlanguagespecifics[#2]\fi +% % the next line catches the case that specifics are enabled *before* they are defined +% \expandafter\ifx\csname\??la\languageencoding#2\??la\endcsname\relax\forgetlanguagespecifics[#2]\fi +% \appendvalue{\??la\languageencoding#2\??la}{#1}% +% \bgroup +% \setbox\scratchbox\hbox{\enablelanguagespecifics[#2]}% +% \ifdim\wd\scratchbox>\zeropoint +% \showmessage\m!linguals7{\currentencoding-#2,\the\wd\scratchbox\space}\wait +% \else +% \showmessage\m!linguals8{\currentencoding-#2}% +% \fi +% \egroup +% \doif{#2}\currentmainlanguage{\enablelanguagespecifics[#2]}} + +\def\languagespectag#1{\??la\languageencoding#1\??la} + +\long\def\dosetlanguagespecifics#1#2% + {\edef\askedlanguagespecificstag{\languagespectag{#2}}% + \ifcsname\askedlanguagespecificstag\endcsname \else + \expandafter\newtoks\csname\askedlanguagespecificstag\endcsname + \fi + \csname\askedlanguagespecificstag\endcsname\@EA{\the\csname\askedlanguagespecificstag\endcsname#1}% + \bgroup + \setbox\scratchbox\hbox{\enablelanguagespecifics[#2]}% + \ifdim\wd\scratchbox>\zeropoint + \showmessage\m!linguals7{\currentencoding-#2,\the\wd\scratchbox\space}\wait + \else + \showmessage\m!linguals8{\currentencoding-#2}% + \fi + \egroup + \doif{#2}\currentmainlanguage{\enablelanguagespecifics[#2]}} + +\def\forgetlanguagespecifics[#1]% + {\csname\languagespectag{#1}\endcsname\emptytoks} + +%D Enabling them is rather straightforward. We only have to +%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 ? + +\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 +%D The next code makes it possible to disable the specifics. + +% \def\deactivatelanguagespecific#1% +% {\ifundefined{l g s \string#1}% +% \letgvalueempty{l g s \string#1}% signal to prevent dup def +% \bgroup +% \catcode`#1=\@@active +% \uccode`~=`#1 +% \uppercase{\doglobal\appendtoks\dodeactivatetoken{~}\to\everyresetlanguagespecifics}% +% \egroup +% \expanded{\doglobal\noexpand\appendtoks{#1}{\the\catcode`#1}}\to\everyresetlanguagespecifics +% \fi} + +% \def\dodeactivatetoken#1#2#3% test needed to avoid clash with \unprotect +% {\def#1{#2}\ifnum\catcode`#2=\@@active\catcode`#2=#3\relax\fi} + +%D We cannot hook this into the installer since language +%D specifics can be anything. So far, we have the following +%D potentially active characters. + +%D Beware, this should happen under an unprotected regime; +%D thanks to Giuseppe Oblomov Bilotta, who first noticed +%D that something was wrong. + +\protect + +% \deactivatelanguagespecific " +% \deactivatelanguagespecific / +% \deactivatelanguagespecific : +% \deactivatelanguagespecific ; +% \deactivatelanguagespecific ? +% \deactivatelanguagespecific ! + +\unprotect + +% yes or no (taco wins: no) + +% \startlanguagespecifics[nl,cs,sk,fr] +% \lccode`\'=`\' +% \stoplanguagespecifics + +%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. + +% \ifprocessingXML is a nasty dependency + +\appendtoks + \ifprocessingXML \else \resetlanguagespecifics \fi +\to \everylanguage + +\protect \endinput 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-spe.tex b/tex/context/base/lang-spe.tex deleted file mode 100644 index 00b514be2..000000000 --- a/tex/context/base/lang-spe.tex +++ /dev/null @@ -1,242 +0,0 @@ -%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. - -%D This code was originally placed in the language -%D initialization module, but isolating it is clearer. Language -%D specifics evolved out of user demands for special features, -%D like the german active quote. After a while I decided to -%D associate them to languages in a more general way so that we -%D could associate all kind of things with language switching. -%D -%D This is a typical example of functionality that occasionally -%D gets improved based on user input and experience. Much of the -%D code is pretty old and could probabbly be done in better ways. -%D It's probably also the kind of code that has been and will be -%D written over and over again by \TEX\ users around the world, -%D so there are probably better implementations of similar -%D functionality around. Therefore, users are invited to pop in -%D their own handling as long as it does not interfere with -%D existing code. Writing the more obscure macros that deal with -%D this is a good learning experience (catcodes, lccodes, token -%D lists, expansion, \unknown). - -\writestatus{loading}{Context Language Macros / Specifics} - -\unprotect - -%D \macros -%D {everyresetlanguagespecifics,resetlanguagespecifics} -%D -%D Cleanup macros. - -\newevery \everyresetlanguagespecifics \relax - -\def\resetlanguagespecifics - {\ifcase\protectionlevel - \the\everyresetlanguagespecifics - \else % to be translated - % \writestatus\m!systems{don't change language in unprotected mode!}% - \fi} - -\appendtoks - \resetlanguagespecifics -\to \everycleanupfeatures - -%D \macros -%D {startlanguagespecifics,enablelanguagespecifics} -%D -%D Each language has its own typographic pecularities. Some of -%D those can be influenced by parameters, others are handled by -%D the interface, but as soon as specific commands come into -%D view we need another mechanism. In the macro that activates -%D a language, we call \type{\enablelanguagespecifics}. This -%D macro in return calls for the setup of language specific -%D macros. Such specifics are defined as: -%D -%D \starttyping -%D \startlanguagespecifics[de] -%D \installcompoundcharacter "a {\"a} -%D \installcompoundcharacter "e {\"e} -%D \installcompoundcharacter "s {\SS} -%D \stoplanguagespecifics -%D \stoptyping -%D -%D Instead of \type{[du]} we can pass a comma separated -%D list, like \type{[du,nl]}. Next calls to this macro add the -%D specifics to the current list. -%D -%D Before we actually read the specifics, we first take some -%D precautions that will prevent spurious spaces to creep into -%D the list. - -% We should use token registers, but alas, we run out of them and -% \ETEX\ has a bug. Well, let's use a token register now (2006). - -\def\startlanguagespecifics% % we use double to - {\bgroup - \catcode`\^^I=\@@ignore - \catcode`\^^M=\@@ignore - \catcode`\^^L=\@@ignore - \dodoubleempty\dostartlanguagespecifics} % get rid of spaces - -%D The main macro looks quite complicated but actually does -%D nothing special. By embedding \type{\do} we can easily -%D append to the lists and also execute them at will. Just to -%D be sure, we check on spurious spaces. The second dummy -%D argument gobbles spaces. - -\def\languageencoding - {\ifx\characterencoding\nocharacterencoding \else - \characterencoding-% - \fi} - -\long\def\dostartlanguagespecifics[#1][#2]#3\stoplanguagespecifics - {\egroup - \processcommalist[#1]{\dosetlanguagespecifics{#3}}} - -% \long\def\dosetlanguagespecifics#1#2% -% {\ifundefined{\??la\languageencoding#2\??la}\forgetlanguagespecifics[#2]\fi -% % the next line catches the case that specifics are enabled *before* they are defined -% \expandafter\ifx\csname\??la\languageencoding#2\??la\endcsname\relax\forgetlanguagespecifics[#2]\fi -% \appendvalue{\??la\languageencoding#2\??la}{#1}% -% \bgroup -% \setbox\scratchbox\hbox{\enablelanguagespecifics[#2]}% -% \ifdim\wd\scratchbox>\zeropoint -% \showmessage\m!linguals7{\currentencoding-#2,\the\wd\scratchbox\space}\wait -% \else -% \showmessage\m!linguals8{\currentencoding-#2}% -% \fi -% \egroup -% \doif{#2}\currentmainlanguage{\enablelanguagespecifics[#2]}} - -\def\languagespectag#1{\??la\languageencoding#1\??la} - -\long\def\dosetlanguagespecifics#1#2% - {\ifcsname\languagespectag{#2}\endcsname \else - \expandafter\newtoks\csname\languagespectag{#2}\endcsname - \fi - \csname\languagespectag{#2}\endcsname\@EA{\the\csname\languagespectag{#2}\endcsname#1}% - \bgroup - \setbox\scratchbox\hbox{\enablelanguagespecifics[#2]}% - \ifdim\wd\scratchbox>\zeropoint - \showmessage\m!linguals7{\currentencoding-#2,\the\wd\scratchbox\space}\wait - \else - \showmessage\m!linguals8{\currentencoding-#2}% - \fi - \egroup - \doif{#2}\currentmainlanguage{\enablelanguagespecifics[#2]}} - -% \def\forgetlanguagespecifics[#1]% -% {\letvalue{\??la\languageencoding#1\??la}\empty} - -\def\forgetlanguagespecifics[#1]% - {\csname\languagespectag{#1}\endcsname\emptytoks} - -%D Enabling them is rather straightforward. We only have to -%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#1\??la}\emptytoks -% \the\executeifdefined{\??la\languageencoding#1\??la}\emptytoks} % dup ? - -%D \macros -%D {deactivatelanguagespecific} -%D -%D The next code makes it possible to disable the specifics. - -% \def\deactivatelanguagespecific#1% -% {\ifundefined{l g s \string#1}% -% \letgvalueempty{l g s \string#1}% signal to prevent dup def -% \bgroup -% \catcode`#1=\@@active -% \uccode`~=`#1 -% \uppercase{\doglobal\appendtoks\dodeactivatetoken{~}\to\everyresetlanguagespecifics}% -% \egroup -% \expanded{\doglobal\noexpand\appendtoks{#1}{\the\catcode`#1}}\to\everyresetlanguagespecifics -% \fi} - -% \def\dodeactivatetoken#1#2#3% test needed to avoid clash with \unprotect -% {\def#1{#2}\ifnum\catcode`#2=\@@active\catcode`#2=#3\relax\fi} - -%D We cannot hook this into the installer since language -%D specifics can be anything. So far, we have the following -%D potentially active characters. - -%D Beware, this should happen under an unprotected regime; -%D thanks to Giuseppe Oblomov Bilotta, who first noticed -%D that something was wrong. - -\protect - -% \deactivatelanguagespecific " -% \deactivatelanguagespecific / -% \deactivatelanguagespecific : -% \deactivatelanguagespecific ; -% \deactivatelanguagespecific ? -% \deactivatelanguagespecific ! - -\unprotect - -% yes or no (taco wins: no) - -% \startlanguagespecifics[nl,cs,sk,fr] -% \lccode`\'=`\' -% \stoplanguagespecifics - -%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. - -% \ifprocessingXML is a nasty dependency - -\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--

Callbacks are the real asset of . They permit you to hook your own code into the engine. Here we implement a few handy @@ -67,7 +69,6 @@ end)

This does a one-shot.

--ldx]]-- - --[[ldx--

Callbacks may result in 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.

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-deb.lua b/tex/context/base/luat-deb.lua deleted file mode 100644 index a32d923bd..000000000 --- a/tex/context/base/luat-deb.lua +++ /dev/null @@ -1,154 +0,0 @@ --- 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 versions then versions = { } end versions['luat-deb'] = 1.001 -if not lmx then lmx = { } end -if not lmx.variables then lmx.variables = { } 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-default'] = 'ConTeXt Status Information' -lmx.variables['title'] = lmx.variables['title-default'] - -if not tracers then tracers = { } end -if not tracers.list then tracers.list = { } end -if not tracers.strings then tracers.strings = { } end - -tracers.strings.undefined = "undefined" - -function tracers.split(csname) - return csname:match("^(.+):(.+)$") -end - -function tracers.type(csname) - tag, name = tracers.split(csname) - if tag then return tag else return nil end -end - -function tracers.name(csname) - tag, name = tracers.split(csname) - if tag then return name else return csname end -end - -function tracers.cs(csname) - tag, name = tracers.split(csname) - if tracers.types[tag] then - return tracers.types[tag](name) - else - return tracers.primitive(csname) - end -end - -function tracers.dimen(name) - return (tex.dimen[name] and number.topoints(tex.dimen[name])) or tracers.strings.undefined -end - -function tracers.count(name) - return tex.count[name] or tracers.strings.undefined -end - -function tracers.toks(name) - return (tex.toks[name] and string.limit(tex.toks[name],40)) or tracers.strings.undefined -end - -function tracers.primitive(name) - return tex[name] or tracers.strings.undefined -end - -tracers.types = { - ['d'] = tracers.dimen, - ['c'] = tracers.count, - ['t'] = tracers.toks, - ['p'] = tracers.primitive -} - -function tracers.knownlist(name) - return tracers.list[name] and #tracers.list[name] > 0 -end - -function tracers.showdebuginfo() - lmx.set('title', 'ConTeXt Debug Information') - lmx.set('color-background-one', lmx.get('color-background-green')) - lmx.set('color-background-two', lmx.get('color-background-blue')) - lmx.show('context-debug.lmx') - lmx.restore() -end - -function tracers.showerror() - lmx.set('title', 'ConTeXt Error Information') - lmx.set('errormessage', status.lasterrorstring) - lmx.set('linenumber', status.linenumber) - lmx.set('color-background-one', lmx.get('color-background-yellow')) - lmx.set('color-background-two', lmx.get('color-background-purple')) - local filename = status.filename - local linenumber = tonumber(status.linenumber or "0") - if not filename then - lmx.set('filename', 'unknown') - lmx.set('errorcontext', 'error in filename') - elseif type(filename) == "number" then - lmx.set('filename', "") - lmx.set('errorcontext', 'unknown error') - elseif io.exists(filename) then - -- todo: use an input opener so that we also catch utf16 an reencoding - lmx.set('filename', filename) - lines = io.lines(filename) - if lines then - local context = { } - n, m = 1, linenumber - b, e = m-10, m+10 - s = string.len(tostring(e)) - for line in lines do - if n > e then - break - elseif n > b then - if n == m then - context[#context+1] = string.format("%" .. s .. "d",n) .. " >> " .. line - else - context[#context+1] = string.format("%" .. s .. "d",n) .. " " .. line - end - end - n = n + 1 - end - lmx.set('errorcontext', table.concat(context,"\n")) - else - lmx.set('errorcontext', "") - end - else - lmx.set('filename', filename) - lmx.set('errorcontext', 'file not found') - end - lmx.show('context-error.lmx') - lmx.restore() -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 - -tracers.list['scratch'] = { - 0, 2, 4, 6, 8 -} - -tracers.list['internals'] = { - 'p:hsize', 'p:parindent', 'p:leftskip','p:rightskip', - 'p:vsize', 'p:parskip', 'p:baselineskip', 'p:lineskip', 'p:topskip' -} - -tracers.list['context'] = { - 'd:lineheight', - 'c:realpageno', 'c:pageno', 'c:subpageno' -} diff --git a/tex/context/base/luat-deb.tex b/tex/context/base/luat-deb.tex deleted file mode 100644 index 55686ac11..000000000 --- a/tex/context/base/luat-deb.tex +++ /dev/null @@ -1,49 +0,0 @@ -%D \module -%D [ file=luat-deb, -%D version=2005.11.06, -%D title=\CONTEXT\ Communication 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}{Communication Support (initialization)} - -\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 - -\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 - debugger.enable() ; - end - }% -\to \everyjob - -\appendtoks - \ctxlua { - if debugger.tracing() then - debugger.disable() ; - debugger.savestats("\jobname-luacalls.log") ; - end - }% -\to \everybye - -\endinput 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--

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.

--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-- +

These can be used/set by the caller program; mtx-context.lua does it.

+--ldx]]-- + +document.arguments = document.arguments or { } +document.files = document.files or { } --[[ldx--

Please create a namespace within these tables before using them!

@@ -24,3 +34,116 @@ userdata ['my.name'] = { } thirddata['tricks' ] = { } --ldx]]-- + +--[[ldx-- +

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.

+--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{} 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("\n") - f:write("\n") - if jobname then - f:write("\t" .. jobname .. "\n") - end - f:write("\t\n") - for _,v in pairs(sorted(instance.foundintrees)) do -- ipairs - f:write("\t\t" .. v .. "\n") - end - f:write("\t\n") - f:write("\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-- -

This file is used when we want the input handlers to behave like -kpsewhich. What to do with the following:

- - -{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c} -$SELFAUTOLOC : /usr/tex/bin/platform -$SELFAUTODIR : /usr/tex/bin -$SELFAUTOPARENT : /usr/tex - - -

How about just forgetting abou them?

---ldx]]-- - -input = input or { } -input.suffixes = input.suffixes or { } -input.formats = input.formats or { } - -input.suffixes['gf'] = { 'gf' } -input.suffixes['pk'] = { '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-- -

If you wondered abou tsome of the previous mappings, how about -the next bunch:

---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 {#1}} @@ -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-lmx.lua b/tex/context/base/luat-lmx.lua deleted file mode 100644 index b9bab7df1..000000000 --- a/tex/context/base/luat-lmx.lua +++ /dev/null @@ -1,141 +0,0 @@ --- 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 versions then versions = { } end versions['luat-mlx'] = 1.001 - --- we can now use l-xml, and we can also use lpeg - -lmx = { } - -lmx.escapes = { - ['&'] = '&', - ['<'] = '<', - ['>'] = '>', - ['"'] = '"' -} - --- local function p -> ends up in lmx.p, so we need to cast - -lmx.variables = { } - -lmx.variables['title-default'] = 'LMX File' -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) -end - -lmx.converting = false - -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 - end - function lmx.variable(str) - return lmx.variables[str] or "" - end - function lmx.escape(str) - return string.gsub(str:gsub('&','&'),'[<>"]',lmx.escapes) - end - function lmx.type(str) - if str then lmx.print("" .. lmx.escape(str) .. "") end - end - function lmx.pv(str) - lmx.print(lmx.variable(str)) - end - function lmx.tv(str) - lmx.type(lmx.variable(str)) - end - data = data:gsub("<%?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) - definitions[tag] = content - return "" - end) - data = data:gsub("<%?lmx%-resolve%s+(%S-)%s-%?>", function(tag) - return definitions[tag] or "" - end) - data = data:gsub("%c%s-(<%?lua .-%?>)%s-%c", function(lua) - return "\n" .. lua .. " " - end) - data = string.gsub(data .. "","(.-)<%?lua%s+(.-)%?>", function(txt, lua) - txt = txt:gsub("%c+", "\\n") - txt = txt:gsub('"' , '\\"') - txt = txt:gsub("'" , "\\'") - -- txt = string.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() - 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 - -if os.platform == "windows" then - lmx.popupfile = function(filename) os.execute("start " .. filename) end -else - lmx.popupfile = function(filename) os.execute(filename) end -end - -function lmx.show(name) - local lmxfile = lmx.lmxfile(name) - local htmfile = lmx.htmfile(name) - if lmxfile == htmfile then - htmfile = string.gsub(lmxfile, "%.%a+$", "html") - end - lmx.convert(lmxfile, htmfile) - lmx.popupfile(htmfile) -end - --- kind of private - -lmx.restorables = { } - -function lmx.set(key, value) - if not lmx.restorables[key] then - table.insert(lmx.restorables, key) - lmx.variables['@@' .. key] = lmx.variables[key] - end - lmx.variables[key] = value -end - -function lmx.get(key) - return lmx.variables[key] or "" -end - -function lmx.restore() - for _,key in pairs(lmx.restorables) do - lmx.variables[key] = lmx.variables['@@' .. key] - end - lmx.restorables = { } -end - --- command line - -if arg then - if arg[1] == "--show" then if arg[2] then lmx.show (arg[2]) end - elseif arg[1] == "--convert" then if arg[2] then lmx.convert(arg[2], arg[3] or "temp.html") end - end -end diff --git a/tex/context/base/luat-lmx.tex b/tex/context/base/luat-lmx.tex deleted file mode 100644 index cc7fa448f..000000000 --- a/tex/context/base/luat-lmx.tex +++ /dev/null @@ -1,16 +0,0 @@ -%D \module -%D [ file=luat-lmx, -%D version=2005.09.02, -%D title=\CONTEXT\ Lua Macros, -%D subtitle=LMX 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 (lmx)} - -\registerctxluafile{luat-lmx}{1.001} 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-- -

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 structured file. Actually, any logging that -is hooked into callbacks will be \XML\ by default.

---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-- -

This looks pretty ugly but we need to speed things up a bit.

---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("%s",category,format(fmt,...))) -end -function logs.xml.line(fmt,...) -- new - write_nl(format("%s",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("") end end -function logs.xml.push () 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("

") - write_nl("") -end - -function logs.xml.report_output_pages(p,b) - write_nl(format("", p)) - write_nl(format("", 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: - 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("") - end - function input.show_close(name) - texio.write(" ") - input.level = input.level - 1 - end - function input.show_load(name) - texio.write_nl("") -- 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("callback "..k.." is not set") 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("

") - 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(""..p.."") - texio.write_nl(""..b.."") - 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("") - texio.write_nl("") - texio.write_nl("") - end - function input.stop_run() - texio.write_nl("") - end - function input.show_statistics() - for k,v in pairs(status.list()) do - texio.write_nl("log",""..tostring(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-- -

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.

- - -TEXMFCACHE=$TMP;$TEMP;$TMPDIR;$TEMPDIR;$HOME;$TEXMFVAR;$VARTEXMF;. - - -

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.

---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-- -

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).

- -

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.

- -

Examples of usage can be found in the font related code.

---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-tra.lua b/tex/context/base/luat-tra.lua deleted file mode 100644 index 5314b48c6..000000000 --- a/tex/context/base/luat-tra.lua +++ /dev/null @@ -1,145 +0,0 @@ --- 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 - --- the 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 = { } - -local counters = { } -local names = { } -local getinfo = debug.getinfo -local format = string.format - --- 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 '' - 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) - 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-- +

We provide (at least here) two entity handlers. The more extensive +resolver consults a hash first, tries to convert to next, +and finaly calls a handler when defines. When this all fails, the +original entity is returned.

+--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 +--~ +--~ +--~ +--~ +--~ +--~ +--~ + +lxml.directives = { } + +local data = { + setup = { }, + before = { }, + after = { } +} - --~ - --~ - --~ - --~ - --~ - --~ - --~ - - 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("",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 - 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 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-- +

The following helper functions best belong to the lmxl-ini +module. Some are here because we need then in the mk +document and other manuals, others came up when playing with +this module. Since this module is also used in we've +put them here instead of loading mode modules there then needed.

+--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 = { ['&'] = '&', ['<'] = '<', ['>'] = '>', ['"'] = '"' } +--~ 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("<")/"<" + S(">")/">" + S("&")/"&" + 1)^0) +local normal = (1 - S("<&>"))^0 +local special = P("<")/"<" + P(">")/">" + P("&")/"&" +local escaped = Cs(normal * (special * normal)^0) + +-- 100 * 1000 * "oeps< oeps> oeps&" : gsub:lpeg == 0153:0280:0151:0080 (last one by roberto) + +-- unescaped = Cs((S("<")/"<" + S(">")/">" + S("&")/"&" + 1)^0) +-- unescaped = Cs((((P("&")/"") * (P("lt")/"<" + P("gt")/">" + P("amp")/"&") * (P(";")/"")) + 1)^0) +local normal = (1 - S"&")^0 +local special = P("<")/"<" + P(">")/">" + P("&")/"&" +local unescaped = Cs(normal * (special * normal)^0) + +-- 100 * 5000 * "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-- +

This module can be used stand alone but also inside 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.

+--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-- +

We've now arrived at an intersting part: accessing the tree using a subset +of and since we're not compatible we call it . We +will explain more about its usage in other documents.

+--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("\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-- +

An 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:

+ + +r : the root element of the data table +d : the data table of the result +t : the index in the data table of the result + + +

Access to the root and data table makes it possible to construct insert and delete +functions.

+--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-- +

Next come all kind of locators and manipulators. The most generic function here +is xml.filter(root,pattern). All registers functions in the filters namespace +can be path of a search path, as in:

+ + +local r, d, k = xml.filter(root,"/a/b/c/position(4)" + +--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-- +

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.

+--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-- +

The following functions collect elements and texts.

+--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-- +

Often using an iterators looks nicer in the code than passing handler +functions. The book describes how to use coroutines for that +purpose (). This permits +code like:

+ + +for r, d, k in xml.elements(xml.load('text.xml'),"title") do + print(d[k]) +end + + +

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:

+ + +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 + + +

We use the function variants in the filters.

+--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-- +

We've now arrives at the functions that manipulate the tree.

+--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-- +

Here are a few synonyms.

+--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-- +

The following helper functions best belong to the lmxl-ini +module. Some are here because we need then in the mk +document and other manuals, others came up when playing with +this module. Since this module is also used in we've +put them here instead of loading mode modules there then needed.

+--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 = { ['&'] = '&', ['<'] = '<', ['>'] = '>', ['"'] = '"' } +--~ 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("<")/"<" + S(">")/">" + S("&")/"&" + 1)^0) +local normal = (1 - S("<&>"))^0 +local special = P("<")/"<" + P(">")/">" + P("&")/"&" +local escaped = Cs(normal * (special * normal)^0) + +-- 100 * 1000 * "oeps< oeps> oeps&" : gsub:lpeg == 0153:0280:0151:0080 (last one by roberto) + +-- unescaped = Cs((S("<")/"<" + S(">")/">" + S("&")/"&" + 1)^0) +-- unescaped = Cs((((P("&")/"") * (P("lt")/"<" + P("gt")/">" + P("amp")/"&") * (P(";")/"")) + 1)^0) +local normal = (1 - S"&")^0 +local special = P("<")/"<" + P(">")/">" + P("&")/"&" +local unescaped = Cs(normal * (special * normal)^0) + +-- 100 * 5000 * "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([[ +--~ +--~ 01 +--~ 02 +--~ 03 +--~ OK +--~ 05 +--~ 06 +--~ ALSO OK +--~ +--~ ]]) + +--~ 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 = [[ +--~ +--~ +--~ my secret +--~ +--~ ]] + +--~ x = xml.convert([[ +--~ 0102xx03OK +--~ ]]) +--~ 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-- +

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 based one. +The find based parser can be found in l-xml-edu.lua along with other older code.

+ +

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 we also need +this module for process management, like handling and +files.

+ + +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) + + +

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.

+--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-- +

This module can be used stand alone but also inside in +which case it hooks into the tracker code. Therefore we provide a few +functions that set the tracers.

+--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-- +

First a hack to enable namespace resolving. A namespace is characterized by +a . The following function associates a namespace prefix with a +pattern. We use , 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.

+--ldx]]-- + +xml.xmlns = xml.xmlns or { } + +local check = lpeg.P(false) +local parse = check + +--[[ldx-- +

The next function associates a namespace prefix with an . This +normally happens independent of parsing.

+ + +xml.registerns("mml","mathml") + +--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-- +

The next function also registers a namespace, but this time we map a +given namespace prefix onto a registered one, using the given +. This used for attributes like xmlns:m.

+ + +xml.checkns("m","http://www.w3.org/mathml") + +--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-- +

Next we provide a way to turn an into a registered +namespace. This used for the xmlns attribute.

+ + +resolvedns = xml.resolvens("http://www.w3.org/mathml") + + +This returns mml. +--ldx]]-- + +function xml.resolvens(url) + return parse:match(lower(url)) or "" +end + +--[[ldx-- +

A namespace in an element can be remapped onto the registered +one efficiently by using the xml.xmlns table.

+--ldx]]-- + +--[[ldx-- +

This version uses . 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 files that +took 12.5 seconds to load (1.5 for file io and the rest for tree building). With +the implementation we got that down to less 7.3 seconds. Loading the 14 + interface definition files (2.6 meg) went down from 1.05 seconds to 0.55.

+ +

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 + code to it.

+ + + + + + + + + + +

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:

+ + +local x = xml.convert(somestring) + + +

An optional second boolean argument tells this function not to create a root +element.

+--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("Packaging data in an xml like table is done with the following +function. Maybe it will go away (when not used).

+--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-- +

We cannot load an from a filehandle so we need to load +the whole file first. The function accepts a string representing +a filename or a file handle.

+--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-- +

When we inject new elements, we need to convert strings to +valid trees, which is what the next function does.

+--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-- +

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!

+--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-- +

In 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.

+--ldx]]-- + +-- todo: add 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("",edt[1])) + handle("") + elseif etg == "@cm@" then + -- handle(format("",edt[1])) + handle("") + elseif etg == "@cd@" then + -- handle(format("",edt[1])) + handle("") + elseif etg == "@dt@" then + -- handle(format("",edt[1])) + handle("") + 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("",ens,etg)) + handle("") + 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("",etg)) + handle("") + 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-- +

At the cost of some 25% runtime overhead you can first convert the tree to a string +and then handle the lot.

+--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-- +

The next function operated on the content only and needs a handle function +that accepts a string.

+--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-- +

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):

+ + +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 + + +

The save function is given below.

+--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-- +

A few helpers:

+--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-- +

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:

+ + +dt[k] = xml.empty() or xml.empty(dt,k) + +--ldx]]-- + +function xml.empty(dt,k) + if dt and k then + dt[k] = "" + return dt[k] + else + return "" + end +end + +--[[ldx-- +

The next helper assigns a tree (or string). Usage:

+ + +dt[k] = xml.assign(root) or xml.assign(dt,k,root) + +--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-arr.mkiv b/tex/context/base/math-arr.mkiv new file mode 100644 index 000000000..5c6cfc294 --- /dev/null +++ b/tex/context/base/math-arr.mkiv @@ -0,0 +1,439 @@ +%D \module +%D [ file=math-arr, +%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? + +\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 + +%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-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", "" }, + }, + ['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[""] = 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-ext.tex b/tex/context/base/math-ext.tex deleted file mode 100644 index cf332ba00..000000000 --- a/tex/context/base/math-ext.tex +++ /dev/null @@ -1,437 +0,0 @@ -%D \module -%D [ file=math-ext, -%D version=2007.07.19, -%D title=\CONTEXT\ Math Macros, -%D subtitle=Extra Macros, -%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. - -\unprotect - -%D These will be generalized! - -\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 - -%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}% - $\m@th\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 - $\m@th\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-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-- -

Math definitions. This code may move.

---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-- +

Remapping mathematics alphabets.

+--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.mkii b/tex/context/base/math-pln.mkii new file mode 100644 index 000000000..0bacc40a2 --- /dev/null +++ b/tex/context/base/math-pln.mkii @@ -0,0 +1,360 @@ +%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 / 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. + +% \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\undefined \let\displ@y\relax\fi + +\newbox\rootbox + +\def\root#1\of + {\setbox\rootbox\hbox{$\mathsurround\zeropoint\scriptscriptstyle{#1}$}% + \mathpalette\r@@t} + +\def\r@@t#1#2% will be overloaded + {\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\mathhexbox#1#2#3% + {\leavevmode + \hbox{$\mathsurround\zeropoint\mathchar"#1#2#3$}} + +\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-$} + +% must go to math-tex + +\ifx\braceld\undefined + % mkii values + \mathchardef\braceld="37A + \mathchardef\bracerd="37B + \mathchardef\bracelu="37C + \mathchardef\braceru="37D +\fi + +\def\downbracefill + {$\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 + {$\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 + +\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\overrightarrow#1% + {\vbox{\mathsurround\zeropoint\ialign{##\crcr + \rightarrowfill\crcr\noalign{\kern-\onepoint\nointerlineskip} + $\hfil\displaystyle{#1}\hfil$\crcr}}} + +\def\overleftarrow#1% + {\vbox{\mathsurround\zeropoint\ialign{##\crcr + \leftarrowfill\crcr\noalign{\kern-\onepoint\nointerlineskip} + $\hfil\displaystyle{#1}\hfil$\crcr}}} + +\def\skew#1#2#3% + {{\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[]} +\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% can be mkiv'd + {\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\zerocount#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-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-pln.tex b/tex/context/base/math-pln.tex deleted file mode 100644 index ffa16c8f5..000000000 --- a/tex/context/base/math-pln.tex +++ /dev/null @@ -1,355 +0,0 @@ -%D \module -%D [ file=math-pln, -%D version=2001.11.16, -%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 is a temporary module, some of this code will move to -%D the other math modules. - -\unprotect - -\ifx\displ@y\unefined \let\displ@y\relax\fi -\ifx\m@th \unefined \let\m@th \relax\fi - -\newbox\rootbox - -\def\root#1\of% - {\setbox\rootbox\hbox{$\m@th\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@ - \mkern5mu\raise.6\dimen@\copy\rootbox - \mkern-10mu\box\z@} - -\def\mathhexbox#1#2#3% - {\leavevmode - \hbox{$\m@th\mathchar"#1#2#3$}} - -\def\oalign#1% - {\leavevmode - \vtop - {\baselineskip\z@skip \lineskip.25ex% - \ialign{##\crcr#1\crcr}}} - -\def\o@lign - {\lineskiplimit\z@ \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$\m@th\ldots\,$\fi} - -\def\hrulefill - {\leaders\hrule\hfill} - -\def\dotfill - {\cleaders\hbox{$\m@th \mkern1.5mu.\mkern1.5mu$}\hfill} - -\def\rightarrowfill - {$\m@th\smash-\mkern-7mu% - \cleaders\hbox{$\mkern-2mu\smash-\mkern-2mu$}\hfill - \mkern-7mu\mathord\rightarrow$} - -\def\leftarrowfill - {$\m@th\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 - -\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$} - -\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$} - -\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\overrightarrow#1% - {\vbox{\m@th\ialign{##\crcr - \rightarrowfill\crcr\noalign{\kern-\p@\nointerlineskip} - $\hfil\displaystyle{#1}\hfil$\crcr}}} - -\def\overleftarrow#1% - {\vbox{\m@th\ialign{##\crcr - \leftarrowfill\crcr\noalign{\kern-\p@\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} - -\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\p@\vbox{\lineskiplimit\maxdimen\lineskip-.5\p@ - \ialign{$\m@th#1\hfil##\hfil$\crcr#2\crcr=\crcr}}} - -\def\notin% - {\mathrel{\mathpalette\c@ncel\in}} - -\def\c@ncel#1#2% - {\m@th\ooalign{$\hfil#1\mkern1mu/\hfil$\crcr$#1#2$}} - -\def\rightleftharpoons% - {\mathrel{\mathpalette\rlh@{}}} - -\def\rlh@#1% - {\vcenter - {\m@th - \hbox - {\ooalign - {\raise2pt\hbox{$#1\rightharpoonup$}\crcr - $#1\leftharpoondown$}}}} - -\def\buildrel#1\over#2% - {\mathrel{\mathop{\kern\z@#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 - \m@th - \ialign{$##\hfil$&\quad##\hfil\crcr#1\crcr}}% - \right.} - -\def\matrix#1% - {\null - \,% - \vcenter - {\normalbaselines\m@th - \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\p@renwd - -% \setbox0=\hbox{\tenex B} \p@renwd=\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 - &&\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)$}% - \null - \;% - \vbox{\kern\ht\@ne\box\tw@}% - \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 - \m@th - \ialign - {\strut\hfil$\displaystyle{##}$&$\displaystyle{{}##}$\hfil\crcr - #1\crcr}}% - \,} - -\def\@lign % restore inside \displ@y - {\tabskip\z@skip - \everycr{}} - -\def\displaylines#1% - {\displ@y - \tabskip\z@skip - \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\z@skip - &$\@lign\displaystyle{{}##}$\hfil\tabskip\centering - &\llap{$\@lign##$}\tabskip\z@skip\crcr - #1\crcr}} - -\def\leqalignno#1% - {\displ@y - \tabskip\centering - \halign to \displaywidth - {\hfil$\@lign\displaystyle{##}$\tabskip\z@skip - &$\@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.mkii b/tex/context/base/math-run.mkii new file mode 100644 index 000000000..afe5b18b4 --- /dev/null +++ b/tex/context/base/math-run.mkii @@ -0,0 +1,97 @@ +%D \module +%D [ file=math-run, +%D version=2001.23.04, +%D title=\CONTEXT\ Math Macros, +%D subtitle=Runtime Macros, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright=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 Math Macros / Runtime Macros} + +\unprotect + +\ifx\showmathmodern\undefined \global\chardef\showmathmodern\zerocount \fi + +\gdef\showmathcharacters% nearly \showcharacters + {\par + \bgroup + \ifcase\showmathmodern\or\ifx\modern\undefined\chardef\showmathmodern\zerocount\fi\fi + \setuptextrules[\c!bodyfont=,\c!style=] + \starttextrule{math characters -- \currentmathcollection} + \whitespace + \dontcomplain + \forgetall + \def\startmathcollection[##1]{} + \let\stopmathcollection\relax + \dimen0\zeropoint + \dimen2\zeropoint + \def\definemathsymbol {\dosixtupleempty\dodefinemathsymbol} + \def\definemathcharacter{\dosixtupleempty\dodefinemathcharacter} + \def\definemathcommand {\dotripleempty \dodefinemathcommand} + %\newcounter\mathcolor + \def\dodefinemathsymbol[##1][##2][##3][##4][##5][##6]% + {%\doifcolorelse{math \purefamilyhex{##3}}{} + % {\increment\mathcolor + % \definecolor[math \purefamilyhex{##3}][\mathcolor]}% + \setbox0\hbox spread 1em{\mathematics{\getvalue{##1}{}{}{}}}% + \ifdim\wd0>\dimen0 \dimen0=\wd0 \fi + \setbox2\hbox spread 1em{\hbox to 1em{\tttf\purefamilyhex{##3}\hss}\box0 ##1}% + \ifdim\wd2>\dimen2 \dimen2=\wd2 \fi} + \def\dodefinemathcharacter[##1][##2][##3][##4][##5][##6]{} + \def\dodefinemathcommand [##1][##2][##3]##4{} + \readsysfile{\f!mathprefix tex}\donothing\donothing + \readsysfile{\f!mathprefix ams}\donothing\donothing + \edef\encwidth{\the\dimen0} + \dimen0=\hsize + \advance\dimen0 2em + \advance\dimen2 2em + \ifcase\showmathmodern\or\advance\dimen2 4em\fi + \divide \dimen0 by \dimen2 \advance\dimen0 1sp + \edef\enccols{\number\dimen0} + \startcolumns[\c!n=\enccols,\c!distance=2em] + \def\dodefinemathsymbol[##1][##2][##3][##4][##5][##6]% + {%\localcolortrue + %\color + % [math \purefamilyhex{##3}] + {\hbox + {\ifcase\showmathmodern\or + \hbox to \encwidth{\modern\let\mathcollection\nomathcollection\mathematics{\getvalue{##1}{}{}{}}\hss}% + \fi + \hbox to \encwidth{\mathematics{\getvalue{##1}{}{}{}}\hss}% + \hbox to 1em{\tttf\purefamilyhex{##3}\hss}##1}\par}} + \readsysfile{\f!mathprefix tex}\donothing\donothing + \readsysfile{\f!mathprefix ams}\donothing\donothing + \stopcolumns + \stoptextrule + \egroup} + +% \definecolor[math \purefamilyhex{mr}] [darkred] +% \definecolor[math \purefamilyhex{mi}] [darkgreen] +% \definecolor[math \purefamilyhex{sy}] [darkblue] +% \definecolor[math \purefamilyhex{ex}] [darkmagenta] +% \definecolor[math \purefamilyhex{nn}] [darkyellow] +% \definecolor[math \purefamilyhex{ma}] [lightred] +% \definecolor[math \purefamilyhex{mb}] [lightgreen] +% \definecolor[math \purefamilyhex{mc}] [lightblue] +% \definecolor[math \purefamilyhex{md}] [lightmagenta] + +\gdef\showmathtoken#1% + {\starttabulate[|lT|lT|lT|l|] + \NC token \NC #1 \NC \NR + \NC collection \NC \ifcsname\@mt@\mathcollection#1\endcsname + \mathcollection + \else\ifcsname\@mt@\nomathcollection#1\endcsname + \nomathcollection + \else + ?% + \fi\fi \NC \NR + \NC visualization \NC \mathematics{\getvalue{#1}} \NC \NR + \NC definition \NC \tttf \@EA\defconvertedcommand\@EA\ascii\csname\@mt@\mathcollection#1\endcsname \ascii \NC \NR + \stoptabulate} + +\protect \endinput diff --git a/tex/context/base/math-run.tex b/tex/context/base/math-run.tex deleted file mode 100644 index affa8d5af..000000000 --- a/tex/context/base/math-run.tex +++ /dev/null @@ -1,95 +0,0 @@ -%D \module -%D [ file=math-run, -%D version=2001.23.04, -%D title=\CONTEXT\ Math Macros, -%D subtitle=Runtime Macros, -%D author=Hans Hagen, -%D date=\currentdate, -%D copyright=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 - -\ifx\showmathmodern\undefined \global\chardef\showmathmodern\zerocount \fi - -\gdef\showmathcharacters% nearly \showcharacters - {\par - \bgroup - \ifcase\showmathmodern\or\ifx\modern\undefined\chardef\showmathmodern\zerocount\fi\fi - \setuptextrules[\c!bodyfont=,\c!style=] - \starttextrule{math characters -- \currentmathcollection} - \whitespace - \dontcomplain - \forgetall - \def\startmathcollection[##1]{} - \let\stopmathcollection\relax - \dimen0\zeropoint - \dimen2\zeropoint - \def\definemathsymbol {\dosixtupleempty\dodefinemathsymbol} - \def\definemathcharacter{\dosixtupleempty\dodefinemathcharacter} - \def\definemathcommand {\dotripleempty \dodefinemathcommand} - %\newcounter\mathcolor - \def\dodefinemathsymbol[##1][##2][##3][##4][##5][##6]% - {%\doifcolorelse{math \purefamilyhex{##3}}{} - % {\increment\mathcolor - % \definecolor[math \purefamilyhex{##3}][\mathcolor]}% - \setbox0\hbox spread 1em{\mathematics{\getvalue{##1}{}{}{}}}% - \ifdim\wd0>\dimen0 \dimen0=\wd0 \fi - \setbox2\hbox spread 1em{\hbox to 1em{\tttf\purefamilyhex{##3}\hss}\box0 ##1}% - \ifdim\wd2>\dimen2 \dimen2=\wd2 \fi} - \def\dodefinemathcharacter[##1][##2][##3][##4][##5][##6]{} - \def\dodefinemathcommand [##1][##2][##3]##4{} - \readsysfile{\f!mathprefix tex}\donothing\donothing - \readsysfile{\f!mathprefix ams}\donothing\donothing - \edef\encwidth{\the\dimen0} - \dimen0=\hsize - \advance\dimen0 2em - \advance\dimen2 2em - \ifcase\showmathmodern\or\advance\dimen2 4em\fi - \divide \dimen0 by \dimen2 \advance\dimen0 1sp - \edef\enccols{\number\dimen0} - \startcolumns[\c!n=\enccols,\c!distance=2em] - \def\dodefinemathsymbol[##1][##2][##3][##4][##5][##6]% - {%\localcolortrue - %\color - % [math \purefamilyhex{##3}] - {\hbox - {\ifcase\showmathmodern\or - \hbox to \encwidth{\modern\let\mathcollection\nomathcollection\mathematics{\getvalue{##1}{}{}{}}\hss}% - \fi - \hbox to \encwidth{\mathematics{\getvalue{##1}{}{}{}}\hss}% - \hbox to 1em{\tttf\purefamilyhex{##3}\hss}##1}\par}} - \readsysfile{\f!mathprefix tex}\donothing\donothing - \readsysfile{\f!mathprefix ams}\donothing\donothing - \stopcolumns - \stoptextrule - \egroup} - -% \definecolor[math \purefamilyhex{mr}] [darkred] -% \definecolor[math \purefamilyhex{mi}] [darkgreen] -% \definecolor[math \purefamilyhex{sy}] [darkblue] -% \definecolor[math \purefamilyhex{ex}] [darkmagenta] -% \definecolor[math \purefamilyhex{nn}] [darkyellow] -% \definecolor[math \purefamilyhex{ma}] [lightred] -% \definecolor[math \purefamilyhex{mb}] [lightgreen] -% \definecolor[math \purefamilyhex{mc}] [lightblue] -% \definecolor[math \purefamilyhex{md}] [lightmagenta] - -\gdef\showmathtoken#1% - {\starttabulate[|lT|lT|lT|l|] - \NC token \NC #1 \NC \NR - \NC collection \NC \ifcsname\@mt@\mathcollection#1\endcsname - \mathcollection - \else\ifcsname\@mt@\nomathcollection#1\endcsname - \nomathcollection - \else - ?% - \fi\fi \NC \NR - \NC visualization \NC \mathematics{\getvalue{#1}} \NC \NR - \NC definition \NC \tttf \@EA\defconvertedcommand\@EA\ascii\csname\@mt@\mathcollection#1\endcsname \ascii \NC \NR - \stoptabulate} - -\protect \endinput 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 {file} +%D \pdfimages {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 {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 +%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 : 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 + {<>}% + \immediate\pdfobj + {<>}% + \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 +%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 : 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 + {<>}% + \immediate\pdfobj + {<>}% + \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 {file} -%D \pdfimages {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 {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 -%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 : 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 - {<>}% - \immediate\pdfobj - {<>}% - \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 + +% 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{<>}% \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{<>}% -% \immediate\pdfobj{<>}% -% \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{<>}% \immediate\pdfobj{<>}% @@ -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'] = {

The directional helpers and pen analysis are more or less translated from the code. It really helps that Taco know that source so well. Taco and I spent quite some time on speeding up the and code. There is not -much to gain, especially if on ekeeps in mind that when integrated in +much to gain, especially if one keeps in mind that when integrated in only a part of the time is spent in . Of course an integrated approach is way faster than an external and processing time nears zero.

@@ -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-- +

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.

+--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-- -

Access to nodes is what gives its power. Here we -implement a few helper functions. These functions are rather optimized.

+

Most of the code that had accumulated here is now separated in +modules.

--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-- +

We start with a registration system for atributes so that we can use the +symbolic names later on.

+--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-- +

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 .

+--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-- +

Access to nodes is what gives its power. Here we +implement a few helper functions. These functions are rather optimized.

+--ldx]]-- --[[ldx--

When manipulating node lists in , we will remove @@ -255,963 +98,136 @@ into the engine, but this is a not so natural extension.

also ignore the empty nodes. [This is obsolete!]

--ldx]]-- +nodes = nodes or { } ---[[ldx-- -

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.

---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-- +

The next function is not that much needed but in we use +for debugging node management.

+--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-- +

Here we implement a mechanism for chaining the special functions +that we use in 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.

+--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-- +

This is rather experimental. We need more control and some of this +might become a runtime module instead.

+--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 "" + 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/norm-xtx.tex b/tex/context/base/norm-xtx.tex new file mode 100644 index 000000000..3da944656 --- /dev/null +++ b/tex/context/base/norm-xtx.tex @@ -0,0 +1,18 @@ +%D \module +%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] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +% 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.mkii b/tex/context/base/page-bck.mkii new file mode 100644 index 000000000..0b4ad779a --- /dev/null +++ b/tex/context/base/page-bck.mkii @@ -0,0 +1,593 @@ +%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 + +% messages moved + +% messages moved + +% messages moved + +% messages moved + +% messages moved + +% messages moved + +% messages moved + +% messages moved + +%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 +%D \addtextbackground +%D \addpagebackground +%D \addprintbackground +%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.) + +\def\checkbackground#1% + {\edef\!!stringe{\??ma#1}% + \doifelsevaluenothing{\!!stringe\c!background } + {\doifelsevaluenothing{\!!stringe\c!foregroundcolor} + {\doifelsevalue{\!!stringe\c!frame }\v!on\!!doneatrue + {\doifelsevalue{\!!stringe\c!leftframe }\v!on\!!doneatrue + {\doifelsevalue{\!!stringe\c!rightframe}\v!on\!!doneatrue + {\doifelsevalue{\!!stringe\c!topframe }\v!on\!!doneatrue + {\doifelsevalue{\!!stringe\c!bottomframe }\v!on\!!doneatrue + \!!doneafalse}}}}} + \!!doneatrue} + \!!doneatrue + \if!!donea + \setusage \!!stringe + \else + \resetusage\!!stringe + \fi} + +\def\ifsomebackgroundfound#1% + {\ifusage{\??ma#1}} + +% \def\doifsomebackgroundelse#1#2#3% +% {\ifusage{\??ma#1}#2\else#3\fi} + +\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 + \doifvaluesomething{\??ma#1\c!setups}{\setups[\getvalue{\??ma#1\c!setups}]}% should not produce funny spaces ! + \setbox#2\vbox\fastlocalframed + [\??ma#1] + [\c!component=#1,\c!strut=\v!no,\c!offset=\v!overlay,\c!setups=,% + \c!width=#3,\c!height=#4] + {\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 + \doifvaluesomething{\??ma#3#4\c!setups}{\setups[\getvalue{\??ma#3#4\c!setups}]}% should not produce funny spaces ! + \fastlocalframed + [\??ma#3#4] + [\c!component=#3-#4,\c!offset=\v!overlay,\c!setups=] + {\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. + +\presetlocalframed [\??ma\v!paper] +\presetlocalframed [\??ma\v!page] +\presetlocalframed [\??ma\v!leftpage] +\presetlocalframed [\??ma\v!rightpage] + +\copyparameters + [\??ma\v!paper\c!frame][\??ma\v!page] + [\c!offset,\c!depth,\c!radius,\c!corner,\c!color,\c!screen] + +\copyparameters + [\??ma\v!paper\c!background][\??ma\v!page] + [\c!offset,\c!depth,\c!radius,\c!corner,\c!color,\c!screen] + +\copyparameters + [\??ma\v!page\c!frame][\??ma\v!page] + [\c!offset,\c!depth,\c!radius,\c!corner,\c!color,\c!screen] + +\copyparameters + [\??ma\v!page\c!background][\??ma\v!page] + [\c!offset,\c!depth,\c!radius,\c!corner,\c!color,\c!screen] + +\copyparameters + [\??ma\v!leftpage\c!frame][\??ma\v!leftpage] + [\c!offset,\c!depth,\c!radius,\c!corner,\c!color,\c!screen] + +\copyparameters + [\??ma\v!leftpage\c!background][\??ma\v!leftpage] + [\c!offset,\c!depth,\c!radius,\c!corner,\c!color,\c!screen] + +\copyparameters + [\??ma\v!rightpage\c!frame][\??ma\v!rightpage] + [\c!offset,\c!depth,\c!radius,\c!corner,\c!color,\c!screen] + +\copyparameters + [\??ma\v!rightpage\c!background][\??ma\v!rightpage] + [\c!offset,\c!depth,\c!radius,\c!corner,\c!color,\c!screen] + +%D We save some keying by defining the areas using +%D intermediate commands. The inheritance macro makes sure +%D that copies are efficient. + +\def\dodocommand#1#2% + {\copylocalframed + [\??ma#1#2][\??ma\v!page]% + \getparameters + [\??ma#1#2] + [\c!background=,\c!frame=,\c!color=,\c!screen=\@@rsscreen, + \c!bottomframe=,\c!topframe=,\c!leftframe=,\c!rightframe=]% + \inheritparameter[\??ma][#1#2\c!color][\v!page\c!color]% + \inheritparameter[\??ma][#1#2\c!screen][\v!page\c!screen]% + \inheritparameter[\??ma][#1#2\c!framecolor][\v!page\c!framecolor]% + \inheritparameter[\??ma][#1#2\c!backgroundcolor][\v!page\c!backgroundcolor]% + \inheritparameter[\??ma][#1#2\c!backgroundscreen][\v!page\c!backgroundscreen]} + +%D The stand alone text area inherits from the page too. + +\dodocommand\v!text \empty +\dodocommand\v!hidden\empty + +%D We now define all 25 main areas in a row. + +\def\docommand#1% + {\dodocommand#1\v!leftedge + \dodocommand#1\v!leftmargin + \dodocommand#1\v!text + \dodocommand#1\v!rightmargin + \dodocommand#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\dodocommand\relax \let\docommand\relax + +%D We now set up the individual areas to use reasonable +%D defaults. + +\setupbackgrounds + [\c!state=\c!start] + +\setupbackgrounds + [\v!paper,\v!page,\v!leftpage,\v!rightpage] + [\c!frame=\v!off, + \c!radius=.5\bodyfontsize, + \c!corner=\v!rectangular, + \c!background=, + \c!screen=\@@rsscreen, + \c!color=, + %\c!frameoffset=\getvalue{\??ma\v!page\c!offset}, + %\c!backgroundoffset=\getvalue{\??ma\v!page\c!offset}, + \c!offset=\!!zeropoint, % later set to \v!overlay, watch out ! + \c!depth=\!!zeropoint] + +\def\docommand#1% + {\inheritparameter[\??ma][#1\c!frameoffset][\v!page\c!offset]% + \inheritparameter[\??ma][#1\c!backgroundoffset][\v!page\c!offset]} + +\docommand\v!paper +\docommand\v!page +\docommand\v!leftpage +\docommand\v!rightpage + +%D Again we clean up temporary macros. + +\let\docommand\relax + +%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. + +\presetlocalframed + [\??ma\v!local] + +\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 % \localframed + [\??ma\v!local] + [\c!component=local,\c!frame=\v!off,\c!offset=\v!overlay,\c!setups=,% + \c!location=\v!keep,% when we use \localframed instead of \fastlocalframed + \c!background=\localbackground]% + {\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-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 +%D \addtextbackground +%D \addpagebackground +%D \addprintbackground +%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-bck.tex b/tex/context/base/page-bck.tex deleted file mode 100644 index 10123fec6..000000000 --- a/tex/context/base/page-bck.tex +++ /dev/null @@ -1,615 +0,0 @@ -%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 - -\startmessages dutch library: layouts - 8: achtergronden berekenen -\stopmessages - -\startmessages english library: layouts - 8: calculating backgrounds -\stopmessages - -\startmessages german library: layouts - 8: berechne Hintergrund -\stopmessages - -\startmessages czech library: layouts - 8: pocita se pozadi -\stopmessages - -\startmessages italian library: layouts - 8: calcolo dello sfondo -\stopmessages - -\startmessages norwegian library: layouts - 8: beregner bakgrunn -\stopmessages - -\startmessages romanian library: layouts - 8: se calculeaza fundalurile -\stopmessages - -\startmessages french library: layouts - 8: calcul des arrières-plans -\stopmessages - -%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 -%D \addtextbackground -%D \addpagebackground -%D \addprintbackground -%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.) - -\def\checkbackground#1% - {\edef\!!stringe{\??ma#1}% - \doifelsevaluenothing{\!!stringe\c!background } - {\doifelsevaluenothing{\!!stringe\c!foregroundcolor} - {\doifelsevalue{\!!stringe\c!frame }\v!on\!!doneatrue - {\doifelsevalue{\!!stringe\c!leftframe }\v!on\!!doneatrue - {\doifelsevalue{\!!stringe\c!rightframe}\v!on\!!doneatrue - {\doifelsevalue{\!!stringe\c!topframe }\v!on\!!doneatrue - {\doifelsevalue{\!!stringe\c!bottomframe }\v!on\!!doneatrue - \!!doneafalse}}}}} - \!!doneatrue} - \!!doneatrue - \if!!donea - \setusage \!!stringe - \else - \resetusage\!!stringe - \fi} - -\def\ifsomebackgroundfound#1% - {\ifusage{\??ma#1}} - -% \def\doifsomebackgroundelse#1#2#3% -% {\ifusage{\??ma#1}#2\else#3\fi} - -\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 - \doifvaluesomething{\??ma#1\c!setups}{\setups[\getvalue{\??ma#1\c!setups}]}% should not produce funny spaces ! - \setbox#2\vbox\fastlocalframed - [\??ma#1] - [\c!component=#1,\c!strut=\v!no,\c!offset=\v!overlay,\c!setups=,% - \c!width=#3,\c!height=#4] - {\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 - \doifvaluesomething{\??ma#3#4\c!setups}{\setups[\getvalue{\??ma#3#4\c!setups}]}% should not produce funny spaces ! - \fastlocalframed - [\??ma#3#4] - [\c!component=#3-#4,\c!offset=\v!overlay,\c!setups=] - {\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!linkertekst,\v!rechtertekst,% - \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 - -\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. - -\presetlocalframed [\??ma\v!paper] -\presetlocalframed [\??ma\v!page] -\presetlocalframed [\??ma\v!leftpage] -\presetlocalframed [\??ma\v!rightpage] - -\copyparameters - [\??ma\v!paper\c!frame][\??ma\v!page] - [\c!offset,\c!depth,\c!radius,\c!corner,\c!color,\c!screen] - -\copyparameters - [\??ma\v!paper\c!background][\??ma\v!page] - [\c!offset,\c!depth,\c!radius,\c!corner,\c!color,\c!screen] - -\copyparameters - [\??ma\v!page\c!frame][\??ma\v!page] - [\c!offset,\c!depth,\c!radius,\c!corner,\c!color,\c!screen] - -\copyparameters - [\??ma\v!page\c!background][\??ma\v!page] - [\c!offset,\c!depth,\c!radius,\c!corner,\c!color,\c!screen] - -\copyparameters - [\??ma\v!leftpage\c!frame][\??ma\v!leftpage] - [\c!offset,\c!depth,\c!radius,\c!corner,\c!color,\c!screen] - -\copyparameters - [\??ma\v!leftpage\c!background][\??ma\v!leftpage] - [\c!offset,\c!depth,\c!radius,\c!corner,\c!color,\c!screen] - -\copyparameters - [\??ma\v!rightpage\c!frame][\??ma\v!rightpage] - [\c!offset,\c!depth,\c!radius,\c!corner,\c!color,\c!screen] - -\copyparameters - [\??ma\v!rightpage\c!background][\??ma\v!rightpage] - [\c!offset,\c!depth,\c!radius,\c!corner,\c!color,\c!screen] - -%D We save some keying by defining the areas using -%D intermediate commands. The inheritance macro makes sure -%D that copies are efficient. - -\def\dodocommand#1#2% - {\copylocalframed - [\??ma#1#2][\??ma\v!page]% - \getparameters - [\??ma#1#2] - [\c!background=,\c!frame=,\c!color=,\c!screen=\@@rsscreen, - \c!bottomframe=,\c!topframe=,\c!leftframe=,\c!rightframe=]% - \inheritparameter[\??ma][#1#2\c!color][\v!page\c!color]% - \inheritparameter[\??ma][#1#2\c!screen][\v!page\c!screen]% - \inheritparameter[\??ma][#1#2\c!framecolor][\v!page\c!framecolor]% - \inheritparameter[\??ma][#1#2\c!backgroundcolor][\v!page\c!backgroundcolor]% - \inheritparameter[\??ma][#1#2\c!backgroundscreen][\v!page\c!backgroundscreen]} - -%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 - -%D We now define all 25 main areas in a row. - -\def\docommand#1% - {\dodocommand#1\v!leftedge - \dodocommand#1\v!leftmargin - \dodocommand#1\v!text - \dodocommand#1\v!rightmargin - \dodocommand#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\dodocommand\relax \let\docommand\relax - -%D We now set up the individual areas to use reasonable -%D defaults. - -\setupbackgrounds - [\c!state=\c!start] - -\setupbackgrounds - [\v!paper,\v!page,\v!leftpage,\v!rightpage] - [\c!frame=\v!off, - \c!radius=.5\bodyfontsize, - \c!corner=\v!rectangular, - \c!background=, - \c!screen=\@@rsscreen, - \c!color=, - %\c!frameoffset=\getvalue{\??ma\v!page\c!offset}, - %\c!backgroundoffset=\getvalue{\??ma\v!page\c!offset}, - \c!offset=\!!zeropoint, % later set to \v!overlay, watch out ! - \c!depth=\!!zeropoint] - -\def\docommand#1% - {\inheritparameter[\??ma][#1\c!frameoffset][\v!page\c!offset]% - \inheritparameter[\??ma][#1\c!backgroundoffset][\v!page\c!offset]} - -\docommand\v!paper -\docommand\v!page -\docommand\v!leftpage -\docommand\v!rightpage - -%D Again we clean up temporary macros. - -\let\docommand\relax - -%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. - -\presetlocalframed - [\??ma\v!local] - -\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 % \localframed - [\??ma\v!local] - [\c!component=local,\c!frame=\v!off,\c!offset=\v!overlay,\c!setups=,% - \c!location=\v!keep,% when we use \localframed instead of \fastlocalframed - \c!background=\localbackground]% - {\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{} - {\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.mkii b/tex/context/base/page-ini.mkii new file mode 100644 index 000000000..e5c3aa41a --- /dev/null +++ b/tex/context/base/page-ini.mkii @@ -0,0 +1,1555 @@ +%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 % + +\fi + +\ifx\recalculatebackgrounds\undefined + + \let \recalculatebackgrounds \relax + \let \addmainbackground \gobbleoneargument % + \let \addtextbackground \gobbleoneargument % + \let \addpagebackground \gobbleoneargument % + \let \addprintbackground \gobbleoneargument % + \let \addstatusinfo \gobbleoneargument % + +\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 + \ifspecialbasedsettings + \myshipout{\hbox{\hbox to \zeropoint{\the\pageboundsettings}% + \hbox{\vbox{\dopagebody#1#2\setpagecounters}}}}% + \else + \the\pageboundsettings + \myshipout{\hbox{\vbox{\dopagebody#1#2\setpagecounters}}}% + \fi + \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 + \checkreferences + \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-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 % + +\fi + +\ifx\recalculatebackgrounds\undefined + + \let \recalculatebackgrounds \relax + \let \addmainbackground \gobbleoneargument % + \let \addtextbackground \gobbleoneargument % + \let \addpagebackground \gobbleoneargument % + \let \addprintbackground \gobbleoneargument % + \let \addstatusinfo \gobbleoneargument % + +\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-ini.tex b/tex/context/base/page-ini.tex deleted file mode 100644 index 61cd91b2b..000000000 --- a/tex/context/base/page-ini.tex +++ /dev/null @@ -1,2034 +0,0 @@ -%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 - -% 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} - -\chardef\normalpagebox=255 - -\newbox\pagebox - -\ifx\recalculatelayout\undefined - - \let \recalculatelayout \relax - -\fi - -\ifx\recalculatelogos\undefined - - \let \recalculatelogos \relax - \let \addlogobackground \gobbleoneargument % - -\fi - -\ifx\recalculatebackgrounds\undefined - - \let \recalculatebackgrounds \relax - \let \addmainbackground \gobbleoneargument % - \let \addtextbackground \gobbleoneargument % - \let \addpagebackground \gobbleoneargument % - \let \addprintbackground \gobbleoneargument % - \let \addstatusinfo \gobbleoneargument % - -\fi - -\ifx\realpageno\undefined - - \countdef\realpageno\zerocount \realpageno\plusone - -\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 - -\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 - -\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{-\@M} \let\ejectpenalty\normalejectpenalty -\def\normalsuperpenalty{-\@MM} \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-\@M'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-\@M } % == {\par\break} % plain -% \def\supereject {\par\penalty-\@MM} % 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 - \ifspecialbasedsettings - \myshipout{\hbox{\hbox to \zeropoint{\the\pageboundsettings}% - \hbox{\vbox{\dopagebody#1#2\setpagecounters}}}}% - \else - \the\pageboundsettings - \myshipout{\hbox{\vbox{\dopagebody#1#2\setpagecounters}}}% - \fi - \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 - \checkreferences - \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\ifpaginageblokkeerd \paginageblokkeerdfalse - -% \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 -% \ifpaginageblokkeerd -% % 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 - \ifpaginageblokkeerd - \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\paginageblokkeerdfalse} - -\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\paginageblokkeerdtrue} - -\installpagebreakhandler \v!yes - {\ifpaginageblokkeerd\else - \ejectinsert - \gotonextpage - \ifinsidecolumns % this will move to MUL - \ejectpage % anders soms geen overgang - \fi - \fi} - -\installpagebreakhandler \v!makeup % ?? - {\ifpaginageblokkeerd\else - \eject - \fi} - -\installpagebreakhandler \v!blank - {\ifcase\pageornamentstate - \global\chardef\pageornamentstate\plusone - \fi} - -\installpagebreakhandler \v!no - {\ifpaginageblokkeerd\else - \dosomebreak\nobreak - \fi} - -\installpagebreakhandler \v!preference - {\ifpaginageblokkeerd\else - \ifinsidecolumns % this will move to MUL - \dosomebreak\goodbreak - \else - \testpage[3][\zeropoint]% - \fi - \fi} - -\installpagebreakhandler \v!bigpreference - {\ifpaginageblokkeerd\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): - -\ifx\undefined\normalshipout \let\normalshipout=\shipout \fi - -\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.mkii b/tex/context/base/page-one.mkii new file mode 100644 index 000000000..1affc24d0 --- /dev/null +++ b/tex/context/base/page-one.mkii @@ -0,0 +1,659 @@ +%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 \unvbox + {\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 + \snaptogrid\hbox{\box\botins}% + \else + \unvbox\botins + \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 + \dochecknextindentation\??bk + \dorechecknextindentation} + +% \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-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 \unvbox + {\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-one.tex b/tex/context/base/page-one.tex deleted file mode 100644 index f33aa4602..000000000 --- a/tex/context/base/page-one.tex +++ /dev/null @@ -1,659 +0,0 @@ -%D \module -%D [ file=page-one, -%D version=2000.10.20, -%D title=\CONTEXT\ OTR 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 OTR 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 \unvbox - {\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 - \snaptogrid\hbox{\box\botins}% - \else - \unvbox\botins - \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 - \dochecknextindentation\??bk - \dorechecknextindentation} - -% \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.mkii b/tex/context/base/page-txt.mkii new file mode 100644 index 000000000..9fe73bec1 --- /dev/null +++ b/tex/context/base/page-txt.mkii @@ -0,0 +1,784 @@ +%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. + +% \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 <\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} + \@@plaatspaginanummer + {\ConvertConstantAfter\doifelse\v!date{#6} + {\currentdate} + {% #6{}{}{} -> {} needed for macros that look + % ahead, like \uniqueMPgraphic + \opeenregel\dolimitatetexts{#1#2#5}{#6{}{}{}}}}}}}% + \egroup} + +%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 + \ifundefined{\string\placelayouttextline\textlinestatus}% + \s!unknown + \else + \textlinestatus + \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/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 <\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/page-txt.tex b/tex/context/base/page-txt.tex deleted file mode 100644 index b40ecb16e..000000000 --- a/tex/context/base/page-txt.tex +++ /dev/null @@ -1,784 +0,0 @@ -%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. - -% \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 <\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} - \@@plaatspaginanummer - {\ConvertConstantAfter\doifelse\v!date{#6} - {\currentdate} - {% #6{}{}{} -> {} needed for macros that look - % ahead, like \uniqueMPgraphic - \opeenregel\dolimitatetexts{#1#2#5}{#6{}{}{}}}}}}}% - \egroup} - -%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 - \ifundefined{\string\placelayouttextline\textlinestatus}% - \s!unknown - \else - \textlinestatus - \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 - \box\scratchpagebox - \localstoptextcolor - \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.mkii b/tex/context/base/ppchtex.mkii new file mode 100644 index 000000000..285b0004e --- /dev/null +++ b/tex/context/base/ppchtex.mkii @@ -0,0 +1,3457 @@ +%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 + +% De onderstaande help-informatie (%I) kan worden opgeroepen +% in TeXEdit. De daaropvolgende setup-informatie (%S) kan +% nadat zij is uit deze file is gefilterd met TeXUtil, in +% handleidingen worden gebruikt. In deze file opgenomen +% documentatie (%D en %M) kan worden gebruikt voor een +% technische handleiding. Met %T kunnen templates worden +% gedefinieerd voor TeXEdit. + +%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} + +%\def\getchemicaldimensions#1#2#3% +% {\global\advance\currentchemical by 1 +% \def\docommand##1##2##3% +% {#1=##1\relax#2=##2\relax#3=##3\relax}% +% \doifdefinedelse{chemical::\the\currentchemical} +% {\getvalue{chemical::\the\currentchemical}} +% {\docommand{6cm}{4cm}{0cm}}} +% +%\def\savechemicaldimensions% +% {\bgroup +% \writestatus{ppchtex}{saving dimensions in ppchtex.dim}% +% \def\docommand##1##2##3% +% {\immediate\write\scratchwrite +% {\noexpand\setchemicaldimensions{##1}{##2}{##3}}}% +% \immediate\openout\scratchwrite=ppchtex.dim +% \scratchcounter=0 +% \loop +% \ifnum\scratchcounter<\currentchemical +% \advance\scratchcounter by 1 +% \getvalue{chemical::\the\scratchcounter}% +% \repeat +% \immediate\closeout\scratchwrite +% \egroup} +% +%\def\loadchemicaldimensions% oh, how nice it would be to use +% {\bgroup % one of the context read commands +% \global\currentchemical=0 +% \immediate\openin\scratchread=./ppchtex.dim +% \ifeof\scratchread +% \immediate\closein\scratchread +% \global\skipchemicalfalse +% \else +% \immediate\closein\scratchread +% \input ./ppchtex.dim\relax +% \ifnum\currentchemical>0 +% \writestatus{ppchtex}{loading dimensions from ppchtex.dim}% +% \global\skipchemicaltrue +% \else +% \global\skipchemicalfalse +% \fi +% \global\currentchemical=0 +% \global\let\savechemicaldimensions=\relax +% \fi +% \egroup +% \global\let\loadchemicaldimensions=\relax} + +\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 +% \loadchemicaldimensions +% \ifskipchemical +% \def\dostartchemical% +% {\def\dummy[####1]{}\dosingleempty\dummy}% +% \def\chemical% +% {\def\dummy[####1][####2][####3]{}\dotripleempty\dummy}% +% \def\toptext##1{}% +% \def\midtext##1{}% +% \def\bottext##1{}% +% \fi + \dostartchemical} + +\def\stopchemical + {%\ifskipchemical + % \getchemicaldimensions{\dimen0}{\dimen2}{\dimen4}% + % \dimen8=\dimen2\advance\dimen8 by \dimen4 + % \setbox0=\vbox to \dimen8 + % {\vss\hbox to \dimen0{\hss\the\currentchemical\hss}\vss}% + % \wd0=\dimen0\ht0=\dimen2\dp0=\dimen4 + % \chemicalframe{\box0}% + %\else + \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 + %\setchemicaldimensions{\wd2}{\ht2}{\dp2}% + \@@chemicalborder{\box0\box4\box2}% text on top of chemicals + \endgroup + %\fi + \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 evenly ; + 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% +% {\let\chemicalspace=\relax +% \def\dodosimplechemical##1% +% {\dosimplechemical{##1}{}{}}% +% \@EA\processcommalist\@EA[\@@chemicalchemicaloffset,#1]\dodosimplechemical +% \egroup} + +\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 \CONTEXT\ 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 + +\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\@@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/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/ppchtex.tex b/tex/context/base/ppchtex.tex deleted file mode 100644 index a7800acd4..000000000 --- a/tex/context/base/ppchtex.tex +++ /dev/null @@ -1,3438 +0,0 @@ -%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 - -% De onderstaande help-informatie (%I) kan worden opgeroepen -% in TeXEdit. De daaropvolgende setup-informatie (%S) kan -% nadat zij is uit deze file is gefilterd met TeXUtil, in -% handleidingen worden gebruikt. In deze file opgenomen -% documentatie (%D en %M) kan worden gebruikt voor een -% technische handleiding. Met %T kunnen templates worden -% gedefinieerd voor TeXEdit. - -%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} - -\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 - \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} - -%\def\getchemicaldimensions#1#2#3% -% {\global\advance\currentchemical by 1 -% \def\docommand##1##2##3% -% {#1=##1\relax#2=##2\relax#3=##3\relax}% -% \doifdefinedelse{chemical::\the\currentchemical} -% {\getvalue{chemical::\the\currentchemical}} -% {\docommand{6cm}{4cm}{0cm}}} -% -%\def\savechemicaldimensions% -% {\bgroup -% \writestatus{ppchtex}{saving dimensions in ppchtex.dim}% -% \def\docommand##1##2##3% -% {\immediate\write\scratchwrite -% {\noexpand\setchemicaldimensions{##1}{##2}{##3}}}% -% \immediate\openout\scratchwrite=ppchtex.dim -% \scratchcounter=0 -% \loop -% \ifnum\scratchcounter<\currentchemical -% \advance\scratchcounter by 1 -% \getvalue{chemical::\the\scratchcounter}% -% \repeat -% \immediate\closeout\scratchwrite -% \egroup} -% -%\def\loadchemicaldimensions% oh, how nice it would be to use -% {\bgroup % one of the context read commands -% \global\currentchemical=0 -% \immediate\openin\scratchread=./ppchtex.dim -% \ifeof\scratchread -% \immediate\closein\scratchread -% \global\skipchemicalfalse -% \else -% \immediate\closein\scratchread -% \input ./ppchtex.dim\relax -% \ifnum\currentchemical>0 -% \writestatus{ppchtex}{loading dimensions from ppchtex.dim}% -% \global\skipchemicaltrue -% \else -% \global\skipchemicalfalse -% \fi -% \global\currentchemical=0 -% \global\let\savechemicaldimensions=\relax -% \fi -% \egroup -% \global\let\loadchemicaldimensions=\relax} - -\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 -% \loadchemicaldimensions -% \ifskipchemical -% \def\dostartchemical% -% {\def\dummy[####1]{}\dosingleempty\dummy}% -% \def\chemical% -% {\def\dummy[####1][####2][####3]{}\dotripleempty\dummy}% -% \def\toptext##1{}% -% \def\midtext##1{}% -% \def\bottext##1{}% -% \fi - \dostartchemical} - -\def\stopchemical - {%\ifskipchemical - % \getchemicaldimensions{\dimen0}{\dimen2}{\dimen4}% - % \dimen8=\dimen2\advance\dimen8 by \dimen4 - % \setbox0=\vbox to \dimen8 - % {\vss\hbox to \dimen0{\hss\the\currentchemical\hss}\vss}% - % \wd0=\dimen0\ht0=\dimen2\dp0=\dimen4 - % \chemicalframe{\box0}% - %\else - \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 - %\setchemicaldimensions{\wd2}{\ht2}{\dp2}% - \@@chemicalborder{\box0\box4\box2}% text on top of chemicals - \endgroup - %\fi - \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{$\@@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}}% - \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 evenly ; - 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% -% {\let\chemicalspace=\relax -% \def\dodosimplechemical##1% -% {\dosimplechemical{##1}{}{}}% -% \@EA\processcommalist\@EA[\@@chemicalchemicaloffset,#1]\dodosimplechemical -% \egroup} - -\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 \CONTEXT\ 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 - - -\ifCONTEXT \else \protect \endinput \fi - -\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} - -\let\@@chemicalcolor\empty - -\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.mkii b/tex/context/base/prop-ini.mkii new file mode 100644 index 000000000..035a40c93 --- /dev/null +++ b/tex/context/base/prop-ini.mkii @@ -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 + {\setgvalue{\e!start#1}{\dostartproperty{#1}}% + \letgvalue{\e!stop #1}\dostopproperty}% + {\setgvalue{\e!start#1}{\dostartgproperty{#1}}% + \letgvalue{\e!stop #1}\dostopgproperty}}% + {\doifelsevalue{\??py#1\c!global}\v!yes + {\setgvalue{\e!start#2}[##1]{\dostartproperty{##1}}% + \letgvalue{\e!stop #2}\dostopproperty}% + {\setgvalue{\e!start#2}[##1]{\dostartgproperty{##1}}% + \letgvalue{\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-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-ini.tex b/tex/context/base/prop-ini.tex deleted file mode 100644 index 084842fdd..000000000 --- a/tex/context/base/prop-ini.tex +++ /dev/null @@ -1,151 +0,0 @@ -%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\defineproperty - {\dotripleempty\dodefineproperty} - -\def\dodefineproperty[#1]% - {\ifundefined{\??py#1\c!global}% - \expandafter\dododefineproperty - \else - \expandafter\nododefineproperty - \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 ! ! ! ! - \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 - \letgvalue{\??py\s!check#1}\docheckproperty - \doifelsevalue{\??py#1\c!method}\v!command - {\doifelsevalue{\??py#1\c!global}\v!yes - {\setgvalue{\e!start#1}{\dostartproperty{#1}}% - \letgvalue{\e!stop #1}\dostopproperty}% - {\setgvalue{\e!start#1}{\dostartgproperty{#1}}% - \letgvalue{\e!stop #1}\dostopgproperty}}% - {\doifelsevalue{\??py#1\c!global}\v!yes - {\setgvalue{\e!start#2}[##1]{\dostartproperty{##1}}% - \letgvalue{\e!stop #2}\dostopproperty}% - {\setgvalue{\e!start#2}[##1]{\dostartgproperty{##1}}% - \letgvalue{\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--

Regimes take care of converting the input characters into sequences. The conversion tables are loaded at runtime.

--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--

We will hook regime handling code into the input methods.

--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-- -

The following code is rather specific.

---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-- +

The following code is rather specific.

+--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 + -- + -- + -- + -- 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.mkiv b/tex/context/base/sort-def.mkiv deleted file mode 100644 index 8cc92a02e..000000000 --- a/tex/context/base/sort-def.mkiv +++ /dev/null @@ -1,16 +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. - -% nothing here - -\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-- -

This module implements a couple of cleanup methods. We need these -in order to meet the specification. Watch the double -parenthesis; they are needed because otherwise we would pass more -than one argument to .

---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 {<>}% - \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} @@ -1047,32 +1047,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 @@ -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/strc-blk.lua b/tex/context/base/strc-blk.lua new file mode 100644 index 000000000..33dbb0b7c --- /dev/null +++ b/tex/context/base/strc-blk.lua @@ -0,0 +1,145 @@ +if not modules then modules = { } end modules ['strc--blk'] = { + version = 1.001, + 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" +} + +-- this one runs on top of buffers and structure + +local texprint, format, gmatch = tex.print, string.format, string.gmatch + +local ctxcatcodes = tex.ctxcatcodes + +structure = structure or { } +structure.blocks = structure.blocks or { } + +local blocks = structure.blocks + +blocks.collected = blocks.collected or { } +blocks.tobesaved = blocks.tobesaved or { } +blocks.states = blocks.states or { } + +local tobesaved, collected, states = blocks.tobesaved, blocks.collected, blocks.states + +local function initializer() + collected, tobesaved = blocks.collected, blocks.tobesaved +end + +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(ctxcatcodes,format("\\dostarthiddenblock{%s}",name)) + else + texprint(ctxcatcodes,format("\\dostartnormalblock{%s}",name)) + end + if type(data) == "table" then + for i=1,#data do + texprint(data[i]) + end + else + printer:match(data) + end + if hide then + texprint(ctxcatcodes,"\\dostophiddenblock") + else + texprint(ctxcatcodes,"\\dostopnormalblock") + end +end + +function blocks.define(name) + states[name] = { all = "hide" } +end + +function blocks.setstate(state,name,tag) + local all = tag == "" + local tags = not all and aux.settings_to_array(tag) + for n in gmatch(name,"%s*([^,]+)") do + local sn = states[n] + if not sn then + -- error + elseif all then + sn.all = state + else + for _, tag in pairs(tags) do + sn[tag] = state + end + end + 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 + local names = aux.settings_to_set(name) + local all = tag == "" + 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, collected) + for i=1,#result do + local ri = result[i] + local metadata = ri.metadata + if names[metadata.name] then + if all then + blocks.print(name,ri.data,hide) + else + local mtags = metadata.tags + for tag, sta in pairs(tags) do + if mtags[tag] then + blocks.print(name,ri.data,hide) + break + end + end + end + end + end +end + +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 + tobesaved[#tobesaved+1] = { + metadata = { + name = name, + tags = tags, + plus = plus, + minus = minus, + }, + references = { + section = structure.sections.currentid(), + }, + data = data or "error", + } + local allstate = states[name].all + if not next(tags) then + if allstate ~= "hide" then + blocks.print(name,data) + elseif plus then + blocks.print(name,data,true) + end + else + local sn = states[name] + for tag, _ in pairs(tags) do + if sn[tag] == nil then + if allstate ~= "hide" then + blocks.print(name,data) + break + end + elseif sn[tag] ~= "hide" then + blocks.print(name,data) + break + end + end + end + buffers.data[buffer] = nil +end diff --git a/tex/context/base/strc-blk.tex b/tex/context/base/strc-blk.tex new file mode 100644 index 000000000..90d2ff9ab --- /dev/null +++ b/tex/context/base/strc-blk.tex @@ -0,0 +1,110 @@ +%D \module +%D [ file=strc-blk, +%D version=2008.10.20, +%D title=\CONTEXT\ Structure Macros, +%D subtitle=Blockmoves, +%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 / Blockmoves} + +\registerctxluafile{strc-blk}{1.001} + +\unprotect + +% we run on top of buffers and sections +% +% todo: prefix numbers (needs further integration elsewhere) +% check functionality +% alternative files (needs further integration elsewhere) + +\def\blockparameter#1#2{\ifcsname\??tb#1#2\endcsname\csname\??tb#1#2\endcsname\fi} + +\def\setupblockparameters{\dodoubleargument \dosetupblock} % fast one (for compatibility) +\def\setupblock {\dodoubleargumentwithset\dosetupblock} % handles set + +\def\dosetupblock[#1]{\getparameters[\??tb#1]} % [#1][#2]} + +\def\defineblock + {\dosingleargument\dodefineblock} + +\def\dodefineblock[#1]% + {\getparameters + [\??tb#1] + [\c!before=\blank, + \c!after=\blank, + \c!inner=, + \c!style=, + \c!file=]% todo + \ctxlua{structure.blocks.define("#1")}% + \setvalue{\e!begin#1}{\dodoubleempty\dobeginofblock[#1]}% + \letvalue{\e!end#1}\relax} + +\long\def\dobeginofblock[#1][#2]% + {\normalexpanded{\noexpand\dodowithbuffer{@block@}{\e!begin#1}{\e!end#1}} + {}{\ctxlua{structure.blocks.save("#1","#2","@block@")}}}% before after + +\def\dostarthiddenblock + {\startnointerference + \dostartnormalblock} + +\def\dostophiddenblock + {\dostopnormalblock + \stopnointerference} + +% order matters: \c!before (think of: \c!before=\startitemize) + +\let\doblocksetups\gobbleoneargument + +\def\dostartnormalblock#1% name + {\bgroup +\visibletrue + \edef\currentblock{#1}% + \doblocksetups\currentblock + \let\doblocksetups\gobbleoneargument + \blockparameter\currentblock\c!before + \dosetfontattribute{\??tb\currentblock}\c!style + \dosetcolorattribute{\??tb\currentblock}\c!color + \blockparameter\currentblock\c!inner + \ignorespaces} + +\def\dostopnormalblock + {\removeunwantedspaces + \blockparameter\currentblock\c!after + \par % todo: alternative = text, paragraph + \egroup} + +\def\dosetblockstate[#1][#2][#3]% state name tag + {\ctxlua{structure.blocks.setstate("#1","#2","#3")}} + +\def\doselectblocks[#1][#2][#3][#4]% state name tag setups + {\begingroup + \doifassignmentelse{#3} + {\getparameters[\??tb\??tb][\c!criterium=\v!text,#3]% + \def\doblocksetups##1{\getparameters[\??tb##1][#3]}% + \ctxlua{structure.blocks.select("#1","#2","","\@@tb@@tbcriterium")}} + {\getparameters[\??tb\??tb][\c!criterium=\v!text,#4]% + \def\doblocksetups##1{\getparameters[\??tb##1][#4]}% + \ctxlua{structure.blocks.select("#1","#2","#3","\@@tb@@tbcriterium")}}% + \endgroup} + +% hide: save, if [+] also hidden execute +% keep: save and normal execute + +\def\hideblocks{\dotripleempty\dosetblockstate[hide]} +\def\keepblocks{\dotripleempty\dosetblockstate[keep]} + +% use : normal execute unless [-] +% process: hidden execute unless [-] +% select : idem use + +\def\useblocks {\doquadrupleempty\doselectblocks[use]} +\def\processblocks{\doquadrupleempty\doselectblocks[process]} +\def\selectblocks {\doquadrupleempty\doselectblocks[use]} + +\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("<%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 {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 = + +\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 = + +\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 + + + + +
+ Some <b>bold</b> title <b>bold <i>bold</i> oeps</b> and more + +

a paragraph of text

+

another paragraph of text

+
+
+
+ Another <b>bold</b> title <b>bold <i>bold</i> oeps</b> and more + +

a paragraph of text

+

another paragraph of text

+
+
+
+ +% 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{} + {\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 side.

--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.mkii b/tex/context/base/supp-ran.mkii new file mode 100644 index 000000000..d595fffaf --- /dev/null +++ b/tex/context/base/supp-ran.mkii @@ -0,0 +1,122 @@ +%D \module +%D [ file=supp-ran, +%D version=1998.01.21, +%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 \macros +%D {getrandomcount, getrandomdimen, +%D getrandomfloat, getrandomnumber, +%D setrandomseed, getrandomseed} +%D +%D This module load Donald Arseneau's generic file +%D \type{random.tex}. A small shell is needed because we +%D redefine some \TEX\ primitives. We also use different names +%D for the two generators and add an extra one. +%D +%D \starttyping +%D \getrandomcount \countregister {minimum} {maximum} +%D \getrandomdimen \dimenregister {minimum} {maximum} +%D \getrandomnumber \macroname {minimum} {maximum} +%D \getrandomfloat \macroname {minimum} {maximum} +%D \stoptyping +%D +%D Of course the file \type{random.tex} needs to be present. +%D To prevent name clashes, the \CONTEXT\ distribution +%D contains a copy in \type {thrd-ran.tex}. +%D +%D The randomseed can be set by: +%D +%D \starttyping +%d \setrandomseed{number>0} +%D \stoptyping +%D +%D and get by: +%D +%D \starttyping +%D \getrandomseed\randomseed +%D \stoptyping + +\input thrd-ran.tex + +\ifx\uniformdeviate\undefined + + \let\verynormalnextrandom\nextrandom + + \def\normalnextrandom + {\bgroup + \let\time \normaltime + \let\day \normalday + \let\month\normalmonth + \let\year \normalyear + \verynormalnextrandom + \egroup} + +\else + + \writestatus{loading}{using TeX's built in randomizer (overloading macro)} + + % 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. + + \def\nextrandom + {\normalsetrandomseed\randomi\relax + \global\randomi\numexpr\normaluniformdeviate2147483646+1\relax} + + \let\normalnextrandom\nextrandom + +\fi + +\def\nextrandom + {\bgroup + \normalnextrandom + \gdef\nextrandom{\ifcase\randomseedfrozen\normalnextrandom\fi}% + \egroup} + +\chardef\randomseedfrozen\zerocount + +\def\freezerandomseed + {\ifcase\randomseedfrozen + \nextrandom \global\chardef\randomseedfrozen\plusone + \fi} + +\def\defrostrandomseed + {\ifcase\randomseedfrozen\else + \global\chardef\randomseedfrozen\zerocount \nextrandom + \fi} + +\let\getrandomcount\setrannum +\let\getrandomdimen\setrandim + +\def\getrandomnumber#1#2#3% + {\getrandomcount\scratchcounter{#2}{#3}% + \edef#1{\the\scratchcounter}} + +\def\getrandomfloat#1#2#3% + {\getrandomdimen\scratchdimen{#2\points}{#3\points}% + \edef#1{\withoutpt\the\scratchdimen}} + +\unexpanded \def\setrandomseed#1% + {\global\randomi#1\relax} % global added + +\unexpanded \def\getrandomseed#1% + {\edef#1{\number\randomi}} + +\def\getnewrandomseed#1% + {\setrandomseed\minusone % signals thrd-ran to auto reseed + \nextrandom % this signal is needed for the + #1\randomi} % pseudo randomizer (see: third-ran) + +\endinput 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-ran.tex b/tex/context/base/supp-ran.tex deleted file mode 100644 index 8c76ab443..000000000 --- a/tex/context/base/supp-ran.tex +++ /dev/null @@ -1,158 +0,0 @@ -%D \module -%D [ file=supp-ran, -%D version=1998.01.21, -%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}{Third Party Macros / Random Number Generation} - -%D \macros -%D {getrandomcount, getrandomdimen, -%D getrandomfloat, getrandomnumber, -%D setrandomseed, getrandomseed} -%D -%D This module load Donald Arseneau's generic file -%D \type{random.tex}. A small shell is needed because we -%D redefine some \TEX\ primitives. We also use different names -%D for the two generators and add an extra one. -%D -%D \starttyping -%D \getrandomcount \countregister {minimum} {maximum} -%D \getrandomdimen \dimenregister {minimum} {maximum} -%D \getrandomnumber \macroname {minimum} {maximum} -%D \getrandomfloat \macroname {minimum} {maximum} -%D \stoptyping -%D -%D Of course the file \type{random.tex} needs to be present. -%D To prevent name clashes, the \CONTEXT\ distribution -%D contains a copy in \type {thrd-ran.tex}. -%D -%D The randomseed can be set by: -%D -%D \starttyping -%d \setrandomseed{number>0} -%D \stoptyping -%D -%D and get by: -%D -%D \starttyping -%D \getrandomseed\randomseed -%D \stoptyping - -\ifx\nextrandom\undefined - - \readfile{random.tex} - {\writestatus{loading}{Donald Arseneau's 'random.tex' (found)}} - {\writestatus{loading}{Donald Arseneau's 'random.tex' (not found)}} - -\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 - -\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} - -\else - - % Yet untested. - - \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 - - \beginETEX \numexpr - \def\nextrandom - {\normalsetrandomseed\randomi - \global\randomi\numexpr\normaluniformdeviate2147483646+1\relax} - \endETEX - - \let\normalnextrandom\nextrandom - -\fi - -\def\nextrandom - {\bgroup - \normalnextrandom - \gdef\nextrandom{\ifcase\randomseedfrozen\normalnextrandom\fi}% - \egroup} - -\chardef\randomseedfrozen\zerocount - -\def\freezerandomseed - {\ifcase\randomseedfrozen - \nextrandom \global\chardef\randomseedfrozen\plusone - \fi} - -\def\defrostrandomseed - {\ifcase\randomseedfrozen\else - \global\chardef\randomseedfrozen\zerocount \nextrandom - \fi} - -\let\getrandomcount\setrannum -\let\getrandomdimen\setrandim - -\def\getrandomnumber#1#2#3% - {\getrandomcount\scratchcounter{#2}{#3}% - \edef#1{\the\scratchcounter}} - -\def\getrandomfloat#1#2#3% - {\getrandomdimen\scratchdimen{#2\points}{#3\points}% - \edef#1{\withoutpt\the\scratchdimen}} - -\unexpanded \def\setrandomseed#1% - {\global\randomi#1\relax} % global added - -\unexpanded \def\getrandomseed#1% - {\edef#1{\number\randomi}} - -\def\getnewrandomseed#1% - {\setrandomseed\minusone % signals thrd-ran to auto reseed - \nextrandom % this signal is needed for the - #1\randomi} % pseudo randomizer (see: third-ran) - -\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-chr.tex b/tex/context/base/syst-chr.tex deleted file mode 100644 index 085d7429f..000000000 --- a/tex/context/base/syst-chr.tex +++ /dev/null @@ -1,131 +0,0 @@ -%D \module -%D [ file=syst-chr, -%D version=1997.01.03, % moved code -%D title=\CONTEXT\ System Macros, -%D subtitle=Character Related 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. - -\unprotect - -%D We want to have access to the raw alternatives of the -%D special characters. We use a \type {\xdef} instead of -%D \type {\let} because we need an expandable token in a -%D \type {\write}. - -\bgroup - -\catcode`B=\@@begingroup -\catcode`E=\@@endgroup -\catcode`.=\@@escape - -.catcode `.{ 12 .xdef .letteropenbrace B.string{E -.catcode `.} 12 .xdef .letterclosebrace B.string}E -.catcode `.& 12 .xdef .letterampersand B.string&E -.catcode `.< 12 .xdef .letterless B.string 12 .xdef .lettermore B.string>E -.catcode `.# 12 .xdef .letterhash B.string#E -.catcode `." 12 .xdef .letterdoublequote B.string"E -.catcode `.' 12 .xdef .lettersinglequote B.string'E -.catcode `.$ 12 .xdef .letterdollar B.string$E -.catcode `.% 12 .xdef .letterpercent B.string%E -.catcode `.^ 12 .xdef .letterhat B.string^E -.catcode `._ 12 .xdef .letterunderscore B.string_E -.catcode `.| 12 .xdef .letterbar B.string|E -.catcode `.~ 12 .xdef .lettertilde B.string~E -.catcode `.\ 12 .xdef .letterbackslash B.string\E -.catcode `./ 12 .xdef .letterslash B.string/E -.catcode `.? 12 .xdef .letterquestionmark B.string?E -.catcode `.! 12 .xdef .letterexclamationmark B.string!E -.catcode `.@ 12 .xdef .letterat B.string@E -.catcode `.: 12 .xdef .lettercolon B.string:E - - .global .let .letterescape .letterbackslash - .global .let .letterbgroup .letteropenbrace - .global .let .letteregroup .letterclosebrace - .global .let .letterleftbrace .letteropenbrace - .global .let .letterrightbrace .letterclosebrace - -.egroup - -%D \macros % check this one -%D {setcatcodes,uncatcodespecials, -%D uncatcodecharacters,uncatcodespacetokens, -%D setnaturalcatcodes, -%D setverbosecscharacters} -%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} - -\def\uncatcodespecials {\setcatcodetable\nilcatcodes \uncatcodespacetokens} -\def\setnaturalcatcodes {\setcatcodetable\nilcatcodes} -\def\setnormalcatcodes {\setcatcodetable\ctxcatcodes} % maybe \texcatcodes -\def\uncatcodecharacters {\setcatcodetable\nilcatcodes} % was fast version, gone now -\def\uncatcodeallcharacters{\setcatcodetable\nilcatcodes} % was slow one, with restore - -%D Next follows a definition that lets some shortcuts expand to -%D themselves. - -\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 - -%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} - -\def\frenchspacing - {\setfrenchspacing{1000}} - -\def\resetfrenchspacing - {\sfcode`\.3000 \sfcode`\,1250 - \sfcode`\?3000 \sfcode`\!3000 - \sfcode`\:2000 \sfcode`\;1500 } - -\protect \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 's char range but outside the unicode range.

--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 @@ -4641,44 +4656,6 @@ {\comparedresult\plustwo}} {\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 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 = control +\def\^^I{\ } % same for + +%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 = control -\def\^^I{\ } % same for - -%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/tabl-ltb.tex b/tex/context/base/tabl-ltb.tex new file mode 100644 index 000000000..e45fb1bc1 --- /dev/null +++ b/tex/context/base/tabl-ltb.tex @@ -0,0 +1,856 @@ +%D \module +%D [ file=core-ltb, +%D version=2002.10.31, +%D title=\CONTEXT\ Table Macros, +%D subtitle=Line 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. + +% testfile: tfmetrics.tex + +% todo: als nx>1, dan in geval van rek tussenruimte berekenen en optellen +% bij breedte, dus: nx nog niet gebruiken in combinatie met rek ! ! ! ! ! + +% This module is experimental, undocumented, and currently only set up +% eTeX. It provides a mechanism for typesetting very large tables, +% spanning many pages horizontally and vertically, with repeated +% header lines and (entry) columns, tab tracking, color, etc. In does +% two passes over a table, which is why the table goes into a +% buffer or file. As said, tables can be real huge. + +% \BH \BC .. \EC \BC .. \EC \EH % append +% \BR \BC .. \EC \BC .. \EC \ER +% +% or +% +% \NC .. \NC .. \NC \NR (todo: optional last \NC) + +% alternative: +% +% (1) direct run, save content in macro, but only if needed +% +% todo +% +% (2) buffered table content +% +% \startbuffer +% \startlinetablehead +% \stoplinetablehead +% \startlinetablebody +% \stoplinetablebody +% \stopbuffer +% +% \processlinetablebuffer[buffer] +% +% in buffer : head and body +% +% (3) unbuffered run, multipass +% +% - run with starting width zero / prev run +% - clip on prev run +% - flush real widths + +\writestatus{loading}{ConTeXt Table Macros / Line Tables} + +\unprotect + +\chardef\linetablesplitstate\zerocount +\chardef\linetableheadstate \zerocount + +\edef\??ler{\??le:r:} +\edef\??lec{\??le:c:} +\edef\??lew{\??le:w:} +\edef\??leh{\??le:h:} +\edef\??led{\??le:d:} + +\newif\iflinetablepreroll +\newif\ifinlinetable + +\newcount\linetablecolumn +\newcount\linetablesubcol +\newdimen\linetablewidth +\newdimen\linetableheight +\newbox \linetablecell + +\let\noflinetablecolumns\!!zerocount +\let\noflinetablerows \!!zerocount +\let\noflinetablelines \!!zerocount +\let\noflinetableparts \!!zerocount +\let\linetablepart \!!plusone +\let\linetablestep \!!plusone +\let\linetableline \!!zerocount +\let\linetablerow \!!zerocount +\let\linetablerows \!!zerocount + +\initializetablebox \zerocount % holds repeater + +\chardef\linetablehmode \zerocount +\chardef\linetablepage \zerocount +\chardef\linetablerepeat\zerocount + +\def\setuplinetable + {\dotripleempty\dosetuplinetable} + +\def\dosetuplinetable[#1][#2][#3]% + {\ifthirdargument + \getparameters[\??le:#1:#2][#3]% + \else\ifsecondargument + \getparameters[\??lec#1][#2]% + \else + \getparameters[\??le][#1]% + \fi\fi} + +\setuplinetable + [\c!n=\!!maxcard, + \c!lines=\!!maxcard, + \c!nx=\plusone, + \c!nleft=0, + \c!repeat=\v!yes, % when \c!nleft>0, repeat on both pages + \c!before=, + \c!after=, + \c!inbetween=\page, + \c!distance=\zeropoint, + \c!stretch=\v!no, + \c!align=\c!right, + \c!leftoffset=.25ex, + \c!rightoffset=\linetableparameter\c!leftoffset, + \c!maxwidth=\zeropoint, + \c!width=5em, + \c!height=\v!fit, % \v!line = faster + \c!background=, + \c!backgroundcolor=] + +\def\linetableparameter#1% + {\csname\??le#1\endcsname} + +\def\doifelselinetablecparameter#1% + {\ifcsname\??lec\number\linetablecolumn#1\endcsname + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\def\linetablecparameter#1% + {\csname + \ifcsname\??lec\number\linetablecolumn#1\endcsname + \??lec\number\linetablecolumn + \else + \??le + \fi + #1\endcsname} + +\def\linetablerparameter#1% faster, leaner and meaner + {\csname + \ifnum\linetablerow=\zerocount % geen ifcase + \ifcsname\??ler\v!header#1\endcsname + \??ler\v!header#1% + \else\ifcsname\??ler0#1\endcsname + \??ler0#1% + \else + \s!empty + \fi\fi + \else + \ifcsname\??ler\number\linetablerow#1\endcsname + \??ler\number\linetablerow#1% + \else\ifcsname\??ler\v!oddeven\linetablerow#1\endcsname + \??ler\v!oddeven\linetablerow#1% + \else + \s!empty + \fi\fi + \fi + \endcsname} + +\def\setnoftableslines + {\doifelse{\linetableparameter\c!lines}\v!fit + {% whitespace already added by vertical strut + \ifdim\pagegoal<\maxdimen + \scratchdimen\pagegoal + \advance\scratchdimen -\pagetotal + \else + \scratchdimen\textheight + \fi + \getrawnoflines\scratchdimen + \xdef\noflinetablelines{\the\noflines} +\iflinetablepreroll \else \ifnum\noflinetablelines<\plustwo + \page \setnoftableslines +\fi \fi +} + {\xdef\noflinetablelines{\linetableparameter\c!lines}}} + +\def\startlinetablecell + {\dosingleempty\dostartlinetablecell} + +\def\dostartlinetablecell[#1]% + {\global\setbox\linetablecell\hbox\bgroup + \iffirstargument + \getparameters[\??lec\number\linetablecolumn][#1]% + \fi + \xdef\linetablestep{\linetablecparameter\c!nx}% + \ifcase\linetablestep\or + \scratchdimen\linetablecparameter\c!width + \scratchskip \linetablecparameter\c!distance + \else + \scratchdimen \zeropoint + \scratchskip \zeropoint + \scratchcounter\linetablecolumn + \dorecurse\linetablestep + {\advance\scratchdimen\linetablecparameter\c!width + %\advance\scratchskip \linetablecparameter\c!distance + \global\advance \linetablecolumn\plusone + \advance\scratchskip \linetablecparameter\c!distance + }% + \global\linetablecolumn\scratchcounter + \fi + \chardef\linetablemode + \iflinetablepreroll + \ifdim\scratchdimen>\zeropoint \zerocount \else \plustwo \fi + \else + \zerocount + \fi + \ifcase\linetablemode + \ifcase\linetablehmode + % nothing + \or + % fit, keep it simple + \or + \chardef\linetablemode\plusone % line + \else + % some already calculated height + \fi + \fi + \setbox\scratchbox\hbox + \bgroup + \dontcomplain + \hskip\linetablecparameter\c!leftoffset\relax + % 0 = width, unknown height + % 1 = width, fixed height + % 2 = no width, auto hsize + \ifnum\linetablemode<\plustwo + \advance\scratchdimen-\linetablecparameter\c!leftoffset + \advance\scratchdimen-\linetablecparameter\c!rightoffset + \fi + \ifcase\linetablemode + \dosetraggedcommand{\linetablecparameter\c!align}% + \vtop \ifdim\linetableheight>\zeropoint to\linetableheight \fi \bgroup + \hsize\scratchdimen + \raggedcommand + \else + \setalignmentswitch{\linetablecparameter\c!align}% + \hbox \ifcase\linetablemode \or to\scratchdimen \fi \bgroup + \ifcase\alignmentswitch\hss\or\hss\fi + \fi + \dostartattributes{\??lec\number\linetablecolumn}\c!style\c!color\empty + \begstrut \ignorespaces} + +% \def\stoplinetablecell +% {\unskip \endstrut +% \dostopattributes +% \ifcase\linetablemode +% \endgraf +% \else +% \ifcase\alignmentswitch\else\hss\fi +% \fi +% \egroup +% \hskip\linetablecparameter\c!rightoffset +% \egroup +% \iflinetablepreroll +% \box\scratchbox +% \else +% \doif{\linetablecparameter\c!background}\v!color +% {\backgroundline[\linetablecparameter\c!backgroundcolor]}% +% {\box\scratchbox}% +% \fi +% \egroup} + +\newconditional\linetableautoheight \settrue\linetableautoheight + +\def\stoplinetablecell + {\unskip \endstrut + \dostopattributes + \ifcase\linetablemode + \endgraf + \else + \ifcase\alignmentswitch\else\hss\fi + \fi + \egroup + \hskip\linetablecparameter\c!rightoffset + \egroup + \iflinetablepreroll + \box\scratchbox + \else + \doifelse{\linetablecparameter\c!background}\v!color + {\ifconditional\linetableautoheight + \hbox{\blackrule + [ \c!color=\linetablecparameter\c!backgroundcolor, + \c!height=\linetablerparameter{x\c!height}, + \c!depth=\linetablerparameter{x\c!depth}, + \c!width=\wd\scratchbox]% + \hskip-\wd\scratchbox\box\scratchbox}% + \else + \backgroundline[\linetablecparameter\c!backgroundcolor]{\box\scratchbox}% + \fi}% + {\box\scratchbox}% + \fi + \egroup} + +% \def\stoplinetablecell +% {\unskip \endstrut +% \dostopattributes +% \ifcase\linetablemode +% \endgraf +% \else +% \ifcase\alignmentswitch\else\hss\fi +% \fi +% \egroup +% \hskip\linetablecparameter\c!rightoffset +% \egroup +% \iflinetablepreroll +% \box\scratchbox +% \else +% \doifelse{\linetablecparameter\c!background}\v!color +% {\ifconditional\linetableautoheight +% % \hbox{\blackrule +% % [ \c!color=\linetablecparameter\c!backgroundcolor, +% % \c!height=\linetablerparameter{x\c!height}, +% % \c!depth=\linetablerparameter{x\c!depth}, +% % \c!width=\wd\scratchbox]% +% % \hskip-\wd\scratchbox\box\scratchbox}% +% \dp\scratchbox\linetablerparameter{x\c!depth}% +% \ht\scratchbox\linetablerparameter{x\c!height}% +% \framed +% [\c!offset=\v!overlay, +% \c!frameoffset=.5\linewidth, +% \c!leftframe=\v!off,\c!rightframe=\v!off, +% \c!background=\v!color, +% \c!backgroundcolor=\linetablecparameter\c!backgroundcolor% +% ]{\box\scratchbox}% +% \else +% \backgroundline[\linetablecparameter\c!backgroundcolor]{\box\scratchbox}% +% \fi}% +% {\box\scratchbox}% +% \fi +% \egroup} + +\def\savelinetablepart + {\global\setbox\tablebox\linetablepart + \ifnum\linetablepart=\zerocount + \box\scratchbox % just storing + \else + \vbox + {\ifvoid\tablebox\linetablepart\else\unvbox\tablebox\linetablepart\fi + \doif{\linetablerparameter\c!background}\v!color + {\backgroundline[\linetablerparameter\c!backgroundcolor]}% + {\box\scratchbox}% is also arg to \backgroundline + \endgraf + \linetablerparameter\c!after}% + \fi} + +\def\flushlinetableparts + {\doglobal\increment\linetableline + \ifnum\linetableline<\noflinetablelines + % keep collecting + \else + \iflinetablepreroll + % forget about them + \else + \dorecurse\noflinetableparts + {\let\linetablepart\recurselevel + \dp\tablebox\linetablepart\strutdepth + % noindent en endgraf needed else whitespace mess-up! + \whitespace % here not after verticalstrut + \ifdim\topskipgap=\zeropoint\else + \verticalstrut\nobreak\kern-\struttotal\kern-\parskip\nobreak\nointerlineskip % fix topskip + \fi + \noindent\strut\hbox to \hsize{\box\tablebox\linetablepart\hss}\endgraf + \ifnum\linetablepart<\noflinetableparts\relax + \linetableparameter\c!inbetween + \fi}% + \ifnum\linetablerows<\noflinetablerows\relax + \linetableparameter\c!inbetween + \else + % after, later + \fi + \chardef\linetableheadstate\plusthree + \global\setbox\tablebox\zerocount\emptybox % here + \fi + % reset \linetablerow will be an option, currently + % starts at zero after split + \globallet\linetablerow\!!zerocount + \globallet\linetableline\!!zerocount + \global\chardef\linetablepage\zerocount + \global\linetablewidth\zeropoint + \setnoftableslines + \fi} + +\def\startlinetablepart + {\global\linetablesubcol\zerocount + \setbox\scratchbox\hbox\bgroup + \doconvertfont{\linetablerparameter\c!style}% + \startcolor[\linetablerparameter\c!color]% + \ignorespaces} + +\def\stoplinetablepart + {\ifnum\linetablepart>\zerocount + \unskip \unskip % remove last intercolumn skip (distance+fill) + \fi + \stopcolor + \egroup + \iflinetablepreroll \else + \ifcase\linetablepart + % we're collecting the repeater + \else + \scratchdimen\hsize \advance\scratchdimen-\wd\scratchbox\relax + \ifdim\scratchdimen>\linetableparameter\c!stretch\else + \setbox\scratchbox\hbox to \hsize{\unhbox\scratchbox}% + \fi + \fi + \fi} + +\def\checklinetablepart + {\global\advance\linetablewidth\wd\linetablecell + \global\advance\linetablecolumn\linetablestep + \global\advance\linetablesubcol\linetablestep + \relax + %\message{\the\linetablecolumn,\the\linetablesubcol}\wait + % from now on the column counter is already incremented + \ifcase\linetablesplitstate + \iflinetablepreroll \else + \box\linetablecell + % the columncounter is one ahead ! +% \hskip\linetablecparameter\c!afstand + \hskip\scratchskip + \fi + %%% + \donefalse + \ifcase\linetablerepeat\else + % van te voren berekenen + \scratchcounter\linetablecolumn\advance\scratchcounter-\plustwo + \ifnum\linetablerepeat=\scratchcounter + \donetrue % collecting repeater + \fi + \fi + %%%% + \ifdone + % collecting repeater + \else + \ifnum\linetablecolumn>\getvalue{\??le::\linetablepart}\relax + \donetrue + \fi + \fi + \ifdone + \stoplinetablepart + \iflinetablepreroll \else + \savelinetablepart + \fi + \ifcase\linetablepage \or + \global\chardef\linetablepage \plustwo + \else + \global\chardef\linetablepage \plusone + \fi + \doglobal\increment\linetablepart + \global\linetablewidth\wd\tablebox\zerocount + \startlinetablepart + \fi + \else + \donefalse + \!!doneafalse + \ifcase\linetablerepeat\else + % van te voren berekenen + \scratchcounter\linetablecolumn \advance\scratchcounter-\plustwo + \ifnum\linetablerepeat=\scratchcounter + \donetrue % collecting repeater + \fi + \fi + \ifdone + \!!doneatrue + % collecting repeater + \else\ifdim\linetablewidth>\hsize + \donetrue + \else +% \global\advance\linetablewidth\linetablecparameter\c!afstand\relax + \global\advance\linetablewidth\scratchskip + \ifdim\linetablewidth>\hsize % ? + \donetrue + \fi + \fi\fi + \ifdone + \stoplinetablepart + \savelinetablepart + \ifcase\linetablepage \or + \global\chardef\linetablepage \plustwo + \else + \global\chardef\linetablepage \plusone + \fi + \doglobal\increment\linetablepart + \ifnum\linetablepart>\noflinetableparts + \globallet\noflinetableparts\linetablepart + \initializetablebox\linetablepart + \fi + \global\linetablewidth\wd\linetablecell + \startlinetablepart + \if!!doneb \else \ifcase\linetablerepeat \else + % check for left/right page + \ifcase\linetablepage\donetrue\or\donetrue\or\donefalse\fi\ifdone + % insert repeater + \global\advance\linetablewidth\wd\tablebox\zerocount + \iflinetablepreroll\kern\wd\else\unhcopy\fi\tablebox\zerocount + \fi + \fi \fi + \fi + \iflinetablepreroll \else + \box\linetablecell + % the columncounter is one ahead ! +% \hskip\linetablecparameter\c!afstand +% \hskip\scratchskip +\dorecurse\linetablestep{\strut\hfil}% + \hskip\scratchskip + \fi + \fi} + +% \linetableparameter\c!var -> \@@levar (when no classes) + +\def\startlinetablerun % to do: quit when nested + {\bgroup + \inlinetabletrue + % autowidth + \doif{\linetableparameter\c!maxwidth}\v!fit + {\setuplinetable[\c!maxwidth=\zeropoint]}% + \processaction + [\linetableparameter\c!stretch] + [ \v!no=>{\setuplinetable[\c!stretch=\maxdimen]},% no stretch + \v!yes=>{\setuplinetable[\c!stretch=\zeropoint]}]% max stretch + \chardef\linetablerepeat\linetableparameter\c!nleft + \chardef\linetablesplitstate % = + \ifdim\linetableparameter\c!maxwidth>\zeropoint + \zerocount \else \plusone + \fi + % optional prevdepth correction + \iflinetablepreroll + \globallet\noflinetablerows\!!zerocount + \else + \linetableparameter\c!before + \fi + \globallet\linetablerows\!!zerocount + \globallet\noflinetablecolumns\!!zerocount + \globallet\noflinetableparts\!!zerocount + \!!counta\zerocount + \def\docommand##1% + {\doglobal\increment\noflinetableparts + \advance\!!counta##1% + \setxvalue{\??le::\noflinetableparts}{\the\!!counta}}% + \processcommacommand[\linetableparameter\c!n]\docommand + \initializetableboxes\noflinetableparts + \ifcase\linetablerepeat + \globallet\linetablepart\!!plusone + \else + \globallet\linetablepart\!!zerocount % repeater + \fi + \globallet\linetablestep\!!plusone + \globallet\linetableline\!!zerocount + \globallet\linetablerow \!!zerocount + \global\linetablecolumn \zerocount + \global\linetablesubcol \zerocount + \global\linetablewidth \zeropoint +\iflinetablepreroll \else \ifdim\pagetotal>\zeropoint + \verticalstrut\kern-\struttotal +\fi \fi + \setnoftableslines + \checklinetablepage + \let\BR\linetableBR + \let\ER\linetableER + \let\BH\linetableBR + \let\EH\linetableER + \let\BC\linetableBC + \let\EC\linetableEC + \let\NC\linetableNC + \let\NR\linetableNR + \flushlinetablehead} + +\def\stoplinetablerun + {\globallet\linetableline\!!maxcard + \chardef\linetableheadstate\zerocount % blocked + \flushlinetableparts + \iflinetablepreroll \else + \linetableparameter\c!after + \fi + \globallet\linetablepart \!!zerocount + \globallet\noflinetableparts\!!zerocount + \egroup} + +% \def\checklinecolumnwidth +% {\ifundefined{\??lew\number\linetablecolumn}% +% \donetrue +% \else\ifdim\getvalue{\??lew\number\linetablecolumn}<\wd\linetablecell +% \donetrue +% \else +% \donefalse +% \fi\fi +% \ifdone +% \setxvalue{\??lew\number\linetablecolumn}{\the\wd\linetablecell}% +% \fi} +% +% \def\checklinecolumnwidth +% {\ifcsname\??lew\number\linetablecolumn\endcsname +% \ifdim\csname\??lew\number\linetablecolumn\endcsname<\wd\linetablecell +% \donetrue +% \else +% \donefalse +% \fi +% \else +% \donetrue +% \fi +% \ifdone +% \setxvalue{\??lew\number\linetablecolumn}{\the\wd\linetablecell}% +% \fi} + +% \def\checklinecolumnwidth +% {\expandafter\xdef\csname\??lew\number\linetablecolumn\endcsname +% {\expandafter\ifx\csname\??lew\number\linetablecolumn\endcsname\relax +% \the\wd\linetablecell +% \else\ifdim\csname\??lew\number\linetablecolumn\endcsname<\wd\linetablecell +% \the\wd\linetablecell +% \else +% \csname\??lew\number\linetablecolumn\endcsname +% \fi\fi}} + +\def\checklinecolumndimension#1#2#3% + {\expandafter\xdef\csname#1\number#3\endcsname + {\expandafter\ifx\csname#1\number#3\endcsname\relax + \the#2\linetablecell + \else\ifdim\csname#1\number#3\endcsname<#2\linetablecell + \the#2\linetablecell + \else + \csname#1\number#3\endcsname + \fi\fi}} + +\def\checklinecolumnwidth {\checklinecolumndimension\??lew\wd\linetablecolumn} +\def\checklinecolumnheight{\checklinecolumndimension\??leh\ht\linetablerow} +\def\checklinecolumndepth {\checklinecolumndimension\??led\dp\linetablerow} + +\def\linetableBR + {\dosingleempty\dolinetableBR} + +\def\dolinetableBR[#1]% #1 not yet implemented + {\ifnum\linetableheadstate=1\else + \doglobal\increment\linetablerow + \doglobal\increment\linetablerows + \fi + \global\linetablecolumn\plusone + \global\linetablesubcol\plusone +% \linetableheight\linetablerparameter\c!height +% +% \ifx\linetableheight\empty +% % nothing +% \else\ifx\linetableheight\v!fit +% % keep it simple +% \else\ifx\linetableheight\v!line +% \chardef\linetablemode\plusone +% \else +% \!!heighta\linetableheight +% \advance\!!heighta-\strutdepth +% \fi\fi\fi +% + \linetableheight\zeropoint + \edef\!!stringa{\linetablerparameter\c!height}% + \ifx\!!stringa\empty + \chardef\linetablehmode\zerocount + \else\ifx\!!stringa\v!fit + \chardef\linetablehmode\plusone + \else\ifx\!!stringa\v!line + \chardef\linetablehmode\plustwo + \else + \linetableheight\!!stringa + \advance\linetableheight-\strutdepth + \fi\fi\fi +% + \startlinetablepart} + +\def\linetableBC + {\startlinetablecell} + +\def\linetableEC + {\stoplinetablecell + \iflinetablepreroll + \checklinecolumnwidth + \checklinecolumnheight + \checklinecolumndepth + \fi + \checklinetablepart} + +\def\linetableER + {% \stoplinetablecell + % no \box\linetablecell, i.e. dummy columnn, last \NC \NR + \stoplinetablepart + \savelinetablepart + \advance\linetablecolumn \minusone + \ifnum\linetablecolumn>\noflinetablecolumns + \xdef\noflinetablecolumns{\number\linetablecolumn}% + \fi + \flushlinetableparts + \global\linetablecolumn\zerocount + \global\linetablewidth \zeropoint + \ifcase\linetablerepeat + \globallet\linetablepart\!!plusone + \else + \globallet\linetablepart\!!zerocount % repeater + \fi + \checklinetablepage + \flushlinetablehead} + +\def\checklinetablepage + {\global\chardef\linetablepage\zerocount + \ifcase\linetablerepeat \else \ifcase\linetablepage + \doif{\linetableparameter\c!repeat}\v!no + {\global\chardef\linetablepage\doifoddpageelse\plusone\plustwo}% + \fi \fi} + +\def\flushlinetablehead + {\ifcase\linetableheadstate + % 0 blocked + \or + % 1 doing head + \or + % 2 head done + \or + % 3 trigger flush + \chardef\linetableheadstate\plusone + \the\@@linetablehead\relax + \chardef\linetableheadstate\plustwo + \fi} + +\def\linetableNC % first time special treatment + {\relax + \ifcase\linetablecolumn + \linetableBR + \else + \linetableEC + \fi + \linetableBC} % beware, this will result in BR BC EC BC NR + +\def\linetableNR + {\stoplinetablecell % dummy + \linetableER} + +\def\startlinetable + {\startlinetablerun} + +\def\stoplinetable + {\stoplinetablerun} + +\def\startlinetableanalysis + {\bgroup + \linetableprerolltrue + \trialtypesettingtrue + \startlinetablerun} + +\def\stoplinetableanalysis + {\stoplinetablerun + \egroup + \globallet\noflinetablerows\linetablerows + \dorecurse\noflinetablerows % global, from last run {\linetableparameter\c!n} + {%\writestatus{linetable}{\recurselevel->\getvalue{\??lew\recurselevel}}% + \setevalue{\??ler\recurselevel x\c!height}{\getvalue{\??leh\recurselevel}}% + \setevalue{\??ler\recurselevel x\c!depth }{\getvalue{\??led\recurselevel}}% + \letgvalue{\??leh\recurselevel}\!!zeropoint + \letgvalue{\??led\recurselevel}\!!zeropoint} + \dorecurse\noflinetablecolumns % global, from last run {\linetableparameter\c!n} + {%\writestatus{linetable}{\recurselevel->\getvalue{\??lew\recurselevel}}% + \setevalue{\??lec\recurselevel\c!width}{\getvalue{\??lew\recurselevel}}% + \letgvalue{\??lew\recurselevel}\!!zeropoint}} % init next table + +% todo: store in box instead of macro + +\newtoks \@@linetablehead + +\long\def\startlinetablehead#1\stoplinetablehead + {\ifinlinetable + \@@linetablehead\emptytoks + \fi + \chardef\linetableheadstate3 % full + \@@linetablehead{#1}% + \ifinlinetable + \flushlinetablehead + \fi} + +\def\linetableBH + {\ifx\EC\relax + % signal, grabbing lines + \else + \@@linetablehead\emptytoks + \fi + \pushmacro\BC + \pushmacro\EC + \def\BC##1\EC{\appendtoks##1\to\@@linetablehead}% + \let\EC\relax} % signal + +\def\linetableEH + {\popmacro\EC + \popmacro\BC + \@EA\startlinetablehead\the\@@linetablehead\stoplinetablehead} + +\let\startlinetablebody\donothing +\let\stoplinetablebody \donothing + +\def\processlinetablebuffer + {\dosingleempty\doprocesslinetablebuffer} + +\def\doprocesslinetablebuffer[#1]% + {\bgroup + \let\startlinetable\donothing + \let\stoplinetable \donothing + \startlinetableanalysis\getbuffer[#1]\stoplinetableanalysis + \startlinetablerun \getbuffer[#1]\stoplinetablerun + \egroup} + +\def\processlinetablefile#1% + {\bgroup + \let\startlinetable\donothing + \let\stoplinetable \donothing + \startlinetableanalysis\readfile{#1}\donothing\donothing\stoplinetableanalysis + \startlinetablerun \readfile{#1}\donothing\donothing\stoplinetablerun + \egroup} + +\protect \endinput + +\doifnotmode{demo}{\endinput} + +\setuplinetable[n=6,m={2,2,2},lines=25] % m ? + +\setuplinetable[c][1] [width=2cm,background=color,backgroundcolor=red] +\setuplinetable[c][4] [width=3cm,background=color,backgroundcolor=yellow] +\setuplinetable[c][6] [width=3cm,background=color,backgroundcolor=magenta] +\setuplinetable[r][odd] [background=color,backgroundcolor=gray] +\setuplinetable[r][even][background=color,backgroundcolor=green] + +\starttext + +\showframe \showstruts + +\setupcolors[state=start] + +\setuppagenumbering[alternative=doublesided]\page[left] + +\startlinetable +\NC aaa\crlf aaa \NC bb \NC c \NC ddddd \NC eeee \NC ff \NC \NR +\dorecurse{100}{\NC aaa \NC bb \NC c \NC ddddd \NC eeee \NC ff \NC \NR} +\stoplinetable + +\startlinetable +\NC[style=slanted,color=green,background=color,backgroundcolor=darkred,nx=2,uitlijnen=middle] xxx + \NC yy \NC ddddd \NC eeee \NC ff \NC \NR +\dorecurse{100}{\NC aaa \NC bb \NC c \NC ddddd \NC eeee \NC ff \NC \NR} +\stoplinetable + +% \startbuffer[lt] +% \NC aaa\crlf aaa \NC bb \NC c \NC ddddd \NC ee \NC ff \NC \NR +% \NC aaa\crlf aaa \NC b \NC cc \NC ddd \NC eeee \NC f \NC \NR +% \stopbuffer +% +% \processlinetablebuffer[lt] + +\stoptext diff --git a/tex/context/base/tabl-ntb.mkii b/tex/context/base/tabl-ntb.mkii new file mode 100644 index 000000000..1f9a9d574 --- /dev/null +++ b/tex/context/base/tabl-ntb.mkii @@ -0,0 +1,1584 @@ +%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 However, the next alternative also takes care of preceding +%D and following white space. + +% \def\bTBLCELL % why not \doinhibitblank +% {\inhibitblank\doconvertfont\tbltblstyle\empty\everypar{\delayedbegstrut}} + +% \def\eTBLCELL +% {\ifhmode +% \delayedendstrut +% \par % added 13/4/2006 +% \else +% \par +% \ifdim\prevdepth<\zeropoint % =-1000pt ? +% \vskip-\strutdp +% \else +% \removebottomthings +% \fi +% \fi} + +%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% +% {\setxvalue{\@@tblprefix#1:#2:l}{\TBLlevel}% +% \long\setvalue{\@@tblprefix#1:#2:t}% +% {\doifdefined{\@@tblprefix#1:#2:l} +% {\edef\TBLlevel{\getvalue{\@@tblprefix#1:#2:l}}}% +% #3}} + +\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} + +\presetlocalframed[\@@tbl\@@tbl] + +\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 + % 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\setTABLEparameters[\c!y\number\maximumrow][#1]\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 + \expanded{\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{\expanded{\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=]% + \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 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} +\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 + \expanded{\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 + \expanded{\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}} + +\setupTABLE + [\c!frameoffset=.5\linewidth, + \c!backgroundoffset=\v!frame, + \c!framecolor=\s!black, + \c!color=, + \c!style=, + \c!headstyle=\v!bold, + \c!headcolor=, + \c!strut=\v!yes, + \c!autostrut=\v!no, + \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-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 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/tabl-tab.tex b/tex/context/base/tabl-tab.tex new file mode 100644 index 000000000..361369ea2 --- /dev/null +++ b/tex/context/base/tabl-tab.tex @@ -0,0 +1,2507 @@ +%D \module +%D [ file=core-tab, +%D version=1997.10.10, +%D title=\CONTEXT\ Table Macros, +%D subtitle=\TABLE\ Embedding, +%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 Table Macros / TaBlE Embedding} + +% By now it makes more sense to merge the patches into the original +% and clean that one up too. + +% Don't change the splitter: +% +% ... \NR +% \TABLEnoalign{\page}\TABLEhead +% \NC ... + +% e-tex: reverse rows or vadjust or ... in tables +% \ifalign +% \xhrule : calls for 'special' with width +% BUG: +% +% \starttable[|l|l|] +% \HL +% \RL\FR \VL Head 1 \VL Head 2 \VL\FR +% \RL\LR \VL Head A \VL Head B \VL\LR % niet grijs ?? +% \HL +% \VL 1 \VL 2 \VL\FR +% \VL a \VL b \VL\LR +% \HL +% \stoptable + +% melden als in kleur conflict, uitgestelde test op \SR\SR + +% verengelsen +% interface + +% footnotes flushen +% \......TABLE........ namen +% kolommen testen +% unbreakable kop definieren +% voetnoten +% meldingen +% als direct \use{max} dan fout +% \BREAKPOINT +% breedte lijn telt +% errors: ook gray in handle + +% \AR -> als in DL dan \DR + +% nieuw: +% +% \NL / \NL[blanko] is skip, nog default? +% geen \HL in a row +% \HL[n] +% \VL[n] + remembers +% c{colorspec} key +% \HC[color][width] +% \VC[color] +% meldingen row, column, use, advise +% \AR: UITSTELLEN / EXPERIMENTEEL + +% WAARDELOZE ERROR HANDLER +% THIS RENEWED MODULE WORKS OK BUT STILL LOOKS BAD + +%D We felt no need to write our own table building macros, +%D simply because Michael Wichura made a terrific one. This +%D package is quite complete and well documented. In \CONTEXT\ +%D we provide a shell for consistent spacing as well as color +%D support. Implementing these features without adapting the +%D original macros is not trivial. One easilly gets conflicts +%D with \type{\omit}, \type{\span} and \type{\noalign}, which +%D means that we end up postponing and overloading macros, +%D mostly global. Now, let's start with loading the main +%D macros: + +\doifundefined{BeginTable}{\doinputonce{table.tex}} + +\unprotect + +%D \macros +%D {inintable, ifsplittables} +%D +%D First we declare some variables. These show a bit what we +%D are dealing with. First we introdoce some booleans that +%D enable us, inside as well as outside this module, to +%D determine in what mode we are. + +\newif\ifintable +\newif\ifsplittables + +%D \macros +%D {tracetablestrue} +%D +%D When I documented this module, I felt the need for tracing +%D options. After implementing this feature, I also added +%D warnings, error recovery and automatic spacing. + +\newif\iftracetables + +%D We show this feature in an eample that also shows some of +%D the basic table typesetting commands. +%D +%D \startbuffer +%D \starttable[|||] +%D \HL +%D \VL first \VL second \VL\AR +%D \HL +%D \VL alfa \VL 1 \VL\AR +%D \VL beta \VL 2 \VL\AR +%D \VL gamma \VL 3 \VL\AR +%D \HL +%D \stoptable +%D \stopbuffer +%D +%D \startcombination +%D {\tracetablesfalse\getbuffer} {\type{\tracetablesfalse}} +%D {\tracetablestrue\getbuffer} {\type{\tracetablestrue}} +%D \stopcombination +%D +%D This table is specified as: +%D +%D \typebuffer +%D +%D This examples shows about the minimum of commands needed to +%D typeset such a table. In this table, the \type {\AR} is +%D automatically translated into the more primitive (but more +%D verbose) commands \type {\SR}, \type {\FR}, \type {\MR} and +%D \type {\LR} commands. +%D +%D \startbuffer +%D \starttables[|||] +%D \HL +%D \VL first \VL second \VL\AR +%D \HL +%D \VL alfa \VL 1 \VL\AR +%D \VL beta \VL 2 \VL\AR +%D \VL gamma \VL 3 \VL\AR +%D \HL +%D \stoptable +%D \stopbuffer +%D +%D When we use the split table feature, we get a bit more +%D information. +%D +%D {\tracetablesfalse\getbuffer} +%D +%D Sometimes in tables information shows up that is not typed +%D in by the user. These messages give a cue in what aspect a +%D table definition is wrong. +%D +%D \startbuffer +%D \starttable[||||] +%D \HL +%D \VL first second \VL third \VL\AR +%D \HL +%D \VL alfa \VL 1 \VL a \VL\AR +%D \VL beta \VL 2 \VL b \VL +%D \VL gamma \VL \THREE{3} c \VL\AR +%D \HL +%D \stoptable +%D \stopbuffer +%D +%D \typebuffer +%D +%D Those terrible table has three errors, which all show up in +%D typeset messages. Errors cannot always recovered 100\% and +%D therefore can result in two or more succesive messages, like +%D in the last row. +%D +%D \getbuffer + +%D Bringing color into tables is complicated by the mere fact +%D that color is not part of \TEX. The main complication is +%D that we don't know in advance how wide a column will be. I +%D implemented color support in tables in the early 90's +%D because I needed it for some articles on color. I have to +%D admit that I seldom use the mechanism. +%D +%D Most color support in \CONTEXT\ makes use of colored rules. +%D At first sight, one is tempted to implement colors in tables +%D in a similar way, but as said, we don't know the dimensions +%D in advance. It turns out however that we don't have to, +%D simply because alignments take care of stretching rules to +%D the appropritate dimensions. This means that we can provide +%D backgrounds by coloring rules with the height of a row, +%D skipping upwards and finally drawing the content, like in: +%D +%D \gdef\ShowExample +%D {\startfiguretext +%D {none} +%D {\getbuffer} +%D \typebuffer +%D \stopfiguretext} +%D +%D \startbuffer +%D \starttable[|c|c|] +%D \HL +%D \BL[2] \SR +%D \VL test \VL test \VL\SR +%D \HL +%D \VL test \VL test \VL\FR +%D \VL test \VL test \VL\MR +%D \VL test \VL test \VL\LR +%D \HL +%D \stoptable +%D \stopbuffer +%D +%D \ShowExample +%D +%D Just to be complete we show how the other columns can be +%D given a background. Later we will provide more details over +%D the commands used. +%D +%D \startbuffer +%D \starttable[|c|c|c|] +%D \HL +%D \BL[3] \SR +%D \VL test \VL test \VL test \VL\SR +%D \HL +%D \stoptable +%D \stopbuffer +%D +%D \ShowExample +%D +%D \startbuffer +%D \starttable[|c|c|c|] +%D \HL +%D \BC \BL[2] \SR +%D \VL test \VL test \VL test \VL\SR +%D \HL +%D \stoptable +%D \stopbuffer +%D +%D \ShowExample +%D +%D \startbuffer +%D \starttable[|c|c|c|] +%D \HL +%D \BC \BC \BL \SR +%D \VL test \VL test \VL test \VL\SR +%D \HL +%D \stoptable +%D \stopbuffer +%D +%D \ShowExample +%D +%D \startbuffer +%D \starttable[|c|c|c|] +%D \HL +%D \BC \BL \SR +%D \VL test \VL test \VL test \VL\SR +%D \HL +%D \stoptable +%D \stopbuffer +%D +%D \ShowExample +%D +%D \startbuffer +%D \starttable[|c|c|c|] +%D \BL \BL \SR +%D \HL +%D \VL test \VL test \VL test \VL\SR +%D \HL +%D \stoptable +%D \stopbuffer +%D +%D \ShowExample + +%D In these examples we can clearly see that for being a real +%D background, the color or gray specification has to precede +%D the content. Just to keep things simple, we can recall this +%D specification later on: +%D +%D \startbuffer +%D \starttable[|c|c|c|] +%D \BC \BL \SR +%D \HL +%D \VL test \VL test \VL test \VL\SR +%D \HL +%D \BR\FR +%D \VL test \VL test \VL test \VL\FR +%D \BR\MR +%D \VL test \VL test \VL test \VL\MR +%D \BR\LR +%D \VL test \VL test \VL test \VL\LR +%D \HL +%D \stoptable +%D \stopbuffer +%D +%D \ShowExample +%D +%D Close study learns that we can put the specification +%D before or after the \type{\HL}, whatever suits best. Keeping +%D track of these specifications is taken care of by the next +%D variables: + +\newif \ifTABLEgrayline % executing gray line +\newif \ifTABLEgraydone % gray line executed +\newtoks \TABLEgraytoks % gray line specification + +\newif\ifTABLEinbreak + +%D Nog vervangen: + +\def\c!Table{Table} +\def\m!TABLE{TABLE} + +%D We already saw that the table macros report errors and +%D provide automatic spacing. These features can only be +%D implemented by keeping track of the state, often the last +%D command on a row. + +\chardef\TABLEunknown = 0 + +\chardef\TABLEseparaterow = 1 +\chardef\TABLEfirstrow = 2 +\chardef\TABLEmidrow = 3 +\chardef\TABLElastrow = 4 +\chardef\TABLErule = 5 +\chardef\TABLEskip = 6 +\chardef\TABLEautorow = 7 + +\chardef\TABLEforcefirstrow = 1 +\chardef\TABLEforcelastrow = 2 + +\chardef\TABLEmissingrow = 1 +\chardef\TABLEmissingcolumn = 2 +\chardef\TABLEspanoverflow = 3 +\chardef\TABLEdivisionoverflow = 4 + +%D We store these states using efficient \type {\chardef}'s. +%D Like most variables, these are global ones. When needed, +%D especially when we flush the backgrounds, we can temporary +%D disable the assignment. + +\newif\ifsetTABLEaction + +\def\setTABLEaction#1% + {\ifsetTABLEaction\global\chardef\TABLEaction#1\fi} + +\def\setTABLEforce#1% + {\ifsetTABLEaction\global\chardef\TABLEforce#1\fi} + +\def\setTABLEerror#1% + {\global\chardef\TABLEerror#1} + +%D Before we come to using these variables, we redefine and/or +%D adapt some \TABLE\ macros. Within \TABLE's the \type{|} and +%D \type{"} have special meanings in templates and are active +%D during. Their meaning can therefore conflict with those +%D elsewhere defined. To be compatible with traditional \TABLE\ +%D as well as \CONTEXT's \type{||} and the active \type{"} +%D extensions for my german friends, we do some catcode magic. + +\newif\ifForgetTableBarAndQuote \ForgetTableBarAndQuotetrue + +% \bgroup + +% \catcode`\|=\@@active +% \catcode`\"=\@@active +% +% \gdef\pushouterbarandquote +% {\ifForgetTableBarAndQuote +% \ifnum\catcode`\|=\@@active \let\outertablebar |\else\let\outertablebar \relax\fi +% \ifnum\catcode`\"=\@@active \let\outertablequote"\else\let\outertablequote\relax\fi +% \let|\letterbar +% \let"\letterdoublequote +% \fi} +% +% \gdef\popouterbarandquote +% {\ifForgetTableBarAndQuote +% \ifx\outertablebar \relax\else\let|\outertablebar \fi +% \ifx\outertablequote\relax\else\let"\outertablequote\fi +% \else +% \redefinetablebarandquote +% \fi} +% +% \egroup +% +% \def\ObeyTableBarAndQuote +% {\ForgetTableBarAndQuotefalse +% \ifintable +% \redefinetablebarandquote +% \fi} + +\let\ActivateBarAndQuote \relax +\let\ObeyTableBarAndQuote\relax +\let\pushouterbarandquote\relax +\let\popouterbarandquote \relax + +%D \macros +%D {ObeyTableBarAndQuote} +%D +%D As said, the \type{|} and \type{"} active characters are +%D often used for other purposes. By default, the outside +%D meanings are therefore preserved and available inside +%D tables. If for some reason one wants to use the \TABLE\ +%D primitives, one can say: +%D +%D \starttyping +%D \ObeyTableBarAndQuote +%D \stoptyping +%D +%D To keep things verbose, as well as to show what \TABLE\ +%D commands we affect, we show some meanings. + +\def\normalTABLEshortrule {\!ttShortHrule} % \- +\def\normalTABLElongrule {\!ttLongHrule} % \= +\def\normalTABLEfullrule {\!ttFullHrule} % \_ +\def\normalTABLEendofrow {\!ttEndOfRow} % \\ +\def\normalTABLEsimplebar {\unskip\!ttRightGlue&&} % | +\def\normalTABLEcomplexbar {\unskip\!ttRightGlue&\omit\!ttAlternateVrule} % \| +\def\normalTABLEquote {\unskip\!ttRightGlue&\omit&} % " +\def\normalTABLElineformat {\normalTABLEendofrow+} +\def\normalTABLElineending {\normalTABLEendofrow0 } +\def\normalTABLEsinglerule {&\normalTABLElongrule&} +\def\normalTABLEmultirule#1{&\use{#1}\normalTABLElongrule&} + +%D The next hack is dedicated to Tobias, who found out that +%D paragraph entries don't break well. + +\def\TABLEhack{\hskip\zeropoint} + +%D The first attemp to solve this problem was: +%D +%D \starttyping +%D \def\normalTABLEquote% +%D {\unskip\TABLEhack\!ttRightGlue&\omit&\TABLEhack} +%D \stoptyping +%D +%D But, as usual, this interfered with \type {\omit}. +%D +%D The next attempt is redefining some core \TABLE\ macro:. +%D This works ok, but breaks for instance the~\type{b} +%D key handling. +%D +%D \starttyping +%D \def\!tfAdjoinPriorColumn% +%D {\ifnum\!taColumnNumber=0 +%D \!taPreamble=\!taRuleColumnTemplate +%D ... +%D \if!taOnceOnlyTabskip +%D \!thToksEdef\!taDataColumnTemplate= +%D {\TABLEhack####\TABLEhack\tabskip\the\!taLastRegularTabskip} +%D \else +%D \!taDataColumnTemplate{\TABLEhack##\TABLEhack}% +%D \fi +%D ... +%D \ReadFormatKeys} +%D \stoptyping + +% \newdimen\TABLEparheight + +\def\BeginTableParBox#1% + {\setbox\scratchbox\vtop\bgroup % \setbox added + \hsize#1\relax + \dontcomplain + \restoretablelineskips + \normalbaselines + \let~\!ttTie + \let\-\!ttDH + \blank[\v!disable]% % added + \the\EveryTableParBox} + +\def\EndTableParBox + {\removelastskip % itemize or so + \endgraf + \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 + \vtop to \noflines\lineheight{\box\scratchbox}% + \fi % esp between rows + \else % of paragraphs + \egroup + \fi +% \getboxheight\scratchdimen\of\box\scratchbox\relax% compensate for +% \ifdim\scratchdimen>\TABLEparheight % funny depth of +% \global\TABLEparheight\scratchdimen % multi-line box +% \fi % i.e. vtop + \box\scratchbox} + +% We also need to patch away the interfering math switch: + +% \mathpunctuationtrue + +% test, test +% \starttable[|c|] +% \NC1,,10\NC\AR +% \stoptable +% test, test + +\def\!ttBeginTableA[#1]{% + \if #1u% % "unboxed" table + \ifmmode + \def\!ttEndTable{% % user had better be in display math mode + \relax}% % and have only one table at the outer level + \else % user had better be in vertical mode + \bgroup + \def\!ttEndTable{% + \egroup}% + \fi + \else + %\hbox\bgroup $ + %\def\!ttEndTable{% + % \egroup % for the \vtop, \vbox, or \vcenter, yet to come + % $% for math mode + % \egroup}% for the \hbox + %\if #1t% + % \vtop + %\else + % \if #1b% + % \vbox + % \else + % \vcenter % math mode was essential for this + % \fi + %\fi + % + \hbox\bgroup + \def\!ttEndTable{\egroup\egroup}% + \if#1t% + \vtop + \else\if#1b% + \vbox + \else + \def\!ttEndTable{\egroup$\egroup}% + %$\vcenter + \scratchtoks\everymath\everymath\emptytoks$\everymath\scratchtoks\vcenter + \fi\fi + % + \bgroup % for the \vtop, \vbox, or \vcenter + \fi + \advance\!taRecursionLevel 1 % RecursionLevel governs initialization + \let\!ttRightGlue=\relax % This may be changed by \JustCenter, etc + \everycr\emptytoks % ={} + \ifnum \!taRecursionLevel=1 + \!ttInitializeTable + \fi} + +%D The next redefinition is more robust than the original: + +\def\SetTableToWidth#1% + {\doifelsenothing{#1}{\!taTableSpread\emptytoks}{\!taTableSpread{to #1}}} + +% (*) Try this one with \type {direction} and {girection}; +% the \PPCHTEX\ manual is a nice testcase. +% +% \startoverlay +% {\starttable[ | l w(2cm) | w(8cm) | ] +% \HL +% \VL direction \VL \showbaselines \dorecurse{3}{direction }\VL \FR +% \VL direction \VL \showbaselines \dorecurse{3}{direction }\VL \MR +% \VL direction \VL \showbaselines \dorecurse{3}{direction }\VL \LR +% \HL +% \stoptable} +% {\starttable[ | l w(2cm) | p(8cm) | ] +% \HL +% \VL direction \VL \showbaselines \dorecurse{3}{direction }\VL \FR +% \VL direction \VL \showbaselines \dorecurse{3}{direction }\VL \MR +% \VL direction \VL \showbaselines \dorecurse{3}{direction }\VL \LR +% \HL +% \stoptable} +% \stopoverlay +% \vskip2cm +% \starttable[ | l w(2cm) | p(8cm) | ] +% \HL +% \VL direction \VL \showbaselines \dorecurse{3}{direction }\VL \FR +% \VL direction \VL \showbaselines \dorecurse{8}{direction }\VL \LR +% \HL +% \stoptable +% \vskip2cm +% \starttable[ | l w(2cm) | p(8cm) | ] +% \HL +% \VL direction \VL \showbaselines \dorecurse{8}{direction }\VL \FR +% \VL direction \VL \showbaselines \dorecurse{8}{direction }\VL \LR +% \HL +% \stoptable + +%D To give an impression of what the (well documented) source +%D of \TABLE\ looks like, we first implement an alternative for +%D the numeric keys. The quantity keys (\type{q} and \type{Q}) +%D support the more european way of writing numbers: +%D +%D \startnarrower +%D 100.000.000,00 instead of 100,000,000.00 +%D \stopnarrower +%D +%D The next table shows how to use these keys. We use braces +%D instead of brackets because we need brackets to specify the +%D format. +%D +%D \startbuffer +%D \starttable{|q[00,000]|Q[00,00]|} +%D \HL +%D \VL -1,2 \VL 12,35 \VL\FR +%D \VL 11,203 \VL 2,4 \VL\LR +%D \HL +%D \stoptable +%D \stopbuffer +%D +%D \ShowExample +%D +%D Although a more efficient implementation is possible |<|we +%D can for instance share common macros|>| we just adapt a copy +%D of the numeric ones. To permit double loading of this +%D module, we check for the existence of one of the macros. + +\letvalue{!tk<\string q>}=\undefined +\letvalue{!tk<\string Q>}=\undefined + +%D We just copy the original {\em comments}. +%D +%D \em Key \type{q}: quantity item, non||math mode. + +\NewFormatKey q% + {\letempty\!tqStyle + \futurelet\!tnext\!tqTestForBracket} + +%D \em Key \type{Q}: quantity item, math mode. + +\NewFormatKey Q% + {\def\!tqStyle{$}% + \futurelet\!tnext\!tqTestForBracket} + +%D \em Note: the space between a quantity entry and the +%D following \type{|}, \type{"}, or \type{\|} is mandatory. +%D empty quantity entries are not allowed: use \type{{}} or +%D \type{\omit} instead. +%D +%D \em Test for bracket: invoked by the keys \type{q} and +%D \type{Q}. + +\def\!tqTestForBracket + {\ifx[\!tnext + \!thx\!tqGetArgument + \else + \!thx\!tqGetCode + \fi} + +%D \em Get code: e.g. \type{4}, or \type{4,0}, \type{0,4}, or +%D \type{10,2}. + +\def\!tqGetCode#1 % note the blank + {\!tqConvertCode #1,,!} + +%D \em Convert code: e.g. converts above to \type{[0000]}, +%D \type{[0000,]}, \type{[,0000]}, \type{[0000000000,00]}. + +\def\!tqConvertCode #1,#2,#3!% + {\begingroup + \aftergroup\edef + \aftergroup\!ttemp + \aftergroup{% + \aftergroup[% + \!taCountA #1 + \!thLoop + \ifnum \!taCountA>\zerocount + \advance\!taCountA \minusone + \aftergroup0 + \repeat + \def\!ttemp{#3}% + \ifx\!ttemp\empty + \else + \aftergroup, + \!taCountA #2 + \!thLoop + \ifnum\!taCountA>\zerocount + \advance\!taCountA \minusone + \aftergroup0 + \repeat + \fi + \aftergroup]\aftergroup}% + \endgroup\relax + \!thx\!tqGetArgument\!ttemp} + +%D \em Get argument: +%D +%D \starttyping +%D +%D \stoptyping + +\def\!tqGetArgument[#1]% + {\!tqMakeQuantityTemplate\!tqStyle#1,,!} + +%D \em Make quantity template. + +\def\!tqMakeQuantityTemplate#1#2,#3,#4!% #1= or $ + {\def\!ttemp{#4}% + \ifx\!ttemp\empty + \!taDimenC\zeropoint + \else + \setbox0\hbox{\mathsurround\zeropoint #1,#3#1}% + \!taDimenC\wd0 + \fi + \setbox0\hbox{\mathsurround\zeropoint #1#2#1}% + \!thToksEdef\!taDataColumnTemplate + ={\noexpand\!tqSetQuantityItem{\the\wd0 }{\the\!taDimenC}{#1}% + \the\!taDataColumnTemplate}% + \ReadFormatKeys} + +%D \em Set numeric item. + +\def\!tqSetQuantityItem #1#2#3#4 % + {\!tqSetQuantityItemA{#1}{#2}{#3}#4,,!} + +\def\!tqSetQuantityItemA #1#2#3#4,#5,#6!% + {\def\!ttemp{#6}% + \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}. + +% %D We also (have to) define a key for \type{\cap}: +% +% \letvalue{!tk<\string K>}=\undefined +% +% \NewFormatKey K% +% {\ReadFormatKeys b\smallcapped} + +%D A few pages back we saw backgrounds, further on we will see +%D colored rules, and here we provide a means to color the +%D entries in a column. (We can of course always use the normal +%D color commands for individual entries.) We could not use the +%D lowercase~\type{c}, because that one is used to force {\em +%D centering}. +%D +%D \startbuffer +%D \starttable[|C{red}|C{green}|C{blue}|] +%D \VL R(ed) \VL G(reen) \VL B(lue) \VL\SR +%D \stoptable +%D \stopbuffer +%D +%D \ShowExample + +\letvalue{!tk<\string C>}=\undefined + +\NewFormatKey C#1% + {\ReadFormatKeys b{\localstartcolor[#1]} a{\localstopcolor}} + +%D So now we have three new keys: +%D +%D \starttable[|||] +%D \HL +%D \NC \bf key \NC \bf meaning \NC\AR +%D \HL +%D \NC Q[x,y] \NC math mode formatted numbers \NC\AR +%D \NC q[x,y] \NC text mode formatted numbers \NC\AR +%D \NC C{identifier} \NC column entry color \NC\AR +%D \HL +%D \stoptable + +%D To be compatible with the tabulate environment, we also +%D support the \type {l}, \type {c} and \type {r} keys for +%D paragraph entries. + +\letvalue{!tk<\string l>}=\undefined +\letvalue{!tk<\string c>}=\undefined +\letvalue{!tk<\string r>}=\undefined +\letvalue{!tk<\string x>}=\undefined % not that needed + +\NewFormatKey c% + {\prependtoks\raggedcenter\to\!taDataColumnTemplate + \ReadFormatKeys \LeftGlue\hfil \RightGlue\hfil} + +\NewFormatKey l% + {\prependtoks\raggedright\to\!taDataColumnTemplate + \ReadFormatKeys \LeftGlue\empty \RightGlue\hfil} + +\NewFormatKey r% + {\prependtoks\raggedleft\to\!taDataColumnTemplate + \ReadFormatKeys \LeftGlue\hfil \RightGlue\empty} + +\NewFormatKey x% + {\prependtoks\notragged\to\!taDataColumnTemplate + \ReadFormatKeys \LeftGlue\hfil \RightGlue\empty} + +\appendtoks \TABLEparalignment \to \EveryTableParBox + +\def\!tfReFormat#1% + {\the \!taLeftGlue + \vbox{\forgetall\ialign{\span\the\!taDataColumnTemplate\cr#1\cr}}% + \the \!taRightGlue + \kern\zeropoint} % prevents \unskip / really needed + +%D Later on, we're going to implement multiple page table +%D support, therefore the next \TABLE\ macro needs to be +%D slightly adapted, i.c. the penalty is removed. We also +%D add basic color support. + +\def\!ttFullHruleA + {\!ttGetHalfRuleThickness + \startglobalTABLEcolor % added + \hrule\!thHeight\dimen0\!thDepth\dimen0 + \stopglobalTABLEcolor % added + %\penalty0 % removed + \egroup} + +%D We'll see that when we want to give a vertical rule a color, +%D we have to set and reset states. After heavy testing it +%D proved most useful to extend a \TABLE\ primitive with some +%D hooks. One thing to keep in mind is that \type{&} keeps +%D assignments local. Again, we add basic color support. + +\let\TABLEbeforebar\empty +\let\TABLEafterbar \empty + +\def\@VLn{1} +\def\@VLd{.125em} + +\def\do!ttInsertVrule % will be merged in 2005 + {\vrule \!thWidth + \ifnum\!tgCode=\plusone + \ifx\!tgValue\empty + \LineThicknessFactor + \else + \!tgValue + \fi + \LineThicknessUnit + \else + \!tgValue + \fi + \hskip\@VLd} + +\def\!ttInsertVrule + {\hfil + \TABLEbeforebar % added + \startglobalTABLEcolor % added + % we could do without this speedup, some day merge 'm + \ifcase\@VLn\or + \do!ttInsertVrule + \unskip + \else + \dorecurse\@VLn\do!ttInsertVrule + \gdef\@VLn{1}% + \unskip + \fi + \stopglobalTABLEcolor % added + \TABLEafterbar % added + \hfil + &} + +%D The next two macros are only adapted to basis rule +%D color support. + +\def\!tfSetVrule + {\!thToksEdef\!taRuleColumnTemplate= + {\noexpand\hfil + \noexpand\startglobalTABLEcolor % added + \noexpand\vrule + \noexpand\!thWidth + \ifnum\!tgCode=\plusone + \ifx\!tgValue\empty + \the\LineThicknessFactor + \else + \!tgValue + \fi + \!taLTU + \else + \!tgValue + \fi + ####% + \noexpand\hfil + \noexpand\stopglobalTABLEcolor % added + \the\!taRuleColumnTemplate}% + \!tfAdjoinPriorColumn} + +\def\!ttShortHruleA + {\!ttGetHalfRuleThickness + \startglobalTABLEcolor % added + \leaders\hrule\!thHeight\dimen0\!thDepth\dimen0\hfill + \stopglobalTABLEcolor % added + \null + \ignorespaces} + +%D We already showed the next one, but here we slightly adapt +%D the macro by adding an \type{\expandafter}. The space after +%D \type{#1} is crucial! + +\def\normalTABLEcomplexbar#1% + {\unskip\!ttRightGlue&\omit\expandafter\!ttAlternateVrule#1 } + +%D To get rid of interfering \type{\omit}'s when we are +%D checking the number of columns and reporting problems. The +%D extensions concern the second level check, the first +%D subbranch and advancing the column. + +\ifx\mscount\undefined \newcount\mscount \fi + +\def\!ttuse#1% + {\ifnum#1>\plusone + \omit + \global\TABLEdivisionfalse + \scratchcounter\currentTABLEcolumn % added + \advance\scratchcounter #1% % added + \advance\scratchcounter \minusone % added + \ifnum\scratchcounter>\maxTABLEcolumn % added + \def\next % added + {\setTABLEerror\TABLEspanoverflow % added + \handleTABLEerror}% % added + \else % added + \def\next % added + {\global\advance\currentTABLEcolumn #1% % added + \global\advance\currentTABLEcolumn \minusone % added + \mscount#1% \mscount is in Plain + \advance\mscount \minusone + \advance\mscount \mscount + \!thLoop + \ifnum\mscount>\plusone + \spanomit \advance\mscount\minusone + \repeat + \span}% + \fi % added + \else % added + \def\next % conflicts with possible next \omit % added + {\global\advance\currentTABLEcolumn \plusone}% % added + \fi + \next} % added + +% \starttable[|c|c|c|c|] +% \HL +% \VL {test} \VL \TWO{} \VL test \VL\FR +% \DL \DC \DL\DR +% \VL {test} \VL \TWO{} \VL test \VL\LR +% \HL +% \stoptable + +%D All commands that are executed between rows are to be put in +%D \type {\noalign}. We can however not verify if we (that is +%D \TABLE) does or did not enter this mode. A moderate dirty +%D but useful trick is using our own alternative:\footnote{Once +%D one has entered the stage of redefining \TEX\ primitives, +%D such hacks become a second nature. However, redefining \type +%D {\omit} and \type{\span} is not that easy.} + +\def\TABLEnoalign + {\noalign\bgroup\let\noalign\relax\let\next=} + +%D \macros +%D {starttable} +%D +%D The rest of this module is not easy to comprehend, mainly +%D because we have to take care of: +%D +%D \startitemize[packed] +%D \item \type{\startitemize[template]} +%D \item \type{\startitemize{template}} +%D \item \type{\startitemize[predefined]} +%D \stopitemize +%D +%D as well as: +%D +%D \startitemize[continue] +%D \item restart after table break +%D \stopitemize +%D +%D The official specification of the start command is: +%D +%D \showsetup{starttable} + +\newconditional\tablerepeathead +\newconditional\tablerepeattail + +\def\starttable + {\bgroup + \doif\@@tisplit\v!auto + {\ifinsidesplitfloat\let\@@tisplit\v!yes\fi}% + \doifinsetelse\@@tisplit{\v!yes,\v!repeat} + {\def\stoptable{\stoptables\egroup}% + \starttables} + {\doifelsenothing\@@tiframe + {\ifinsidefloat\else\startbaselinecorrection\fi} + {\startframedcontent[\@@tiframe]}% + \postponenotes + \firststagestartTABLE}} + +\def\stoptable + {\chuckTABLEautorow % before the tail, else noalign problem + \insertTABLEtail + \TABLEnoalign{\globalletempty\@@TABLEhead}% + \TABLEnoalign{\globalletempty\@@TABLEtail}% + \finishTABLE + \doifelsenothing\@@tiframe + {\ifinsidefloat\else + \stopbaselinecorrection + \goodbreak % compensates all the nobreaks + \fi} + \stopframedcontent + \egroup} + +%D Before we can grab the argument, we have to make sure that +%D the \CATCODES\ are set. The first stage takes care of that. + +\def\firststagestartTABLE + {\bgroup % kan-ie weg? + \global\intabletrue + \pushouterbarandquote + %catcode`\|=\@@other + \complexorsimple\secondstagestartTABLE} + +\def\simplesecondstagestartTABLE#1% + {\complexsecondstagestartTABLE[{#1}]} + +%D \macros +%D {definetabletemplate} +%D +%D The complex (and main) start macro first takes care of the +%D predefined case. Such a predefined setup looks like: +%D +%D \starttyping +%D \definetabletemplate[test][|||] +%D +%D \starttable[test] +%D \VL test \VL test \VL\AR +%D \VL test \VL test \VL\AR +%D \VL test \VL test \VL\AR +%D \stoptable +%D \stoptyping +%D +%D The implementation of the definition macro is not that +%D complicated: + +\def\definetabletemplate % to be redone + {\bgroup + \catcode`\|=\@@other + \doquadrupleempty\dodefinetabletemplate} + +\def\dodefinetabletemplate[#1][#2][#3][#4]% + {\ifsecondargument + \setgvalue{\c!Table#1}{\douseTABLEtemplate{#2}{#3}{#4}}% + \fi + \egroup} + +\def\douseTABLEtemplate#1#2#3% + {\gdef\TABLEhead{\getvalue{@@TABLEhead#2}}% + \gdef\TABLEtail{\getvalue{@@TABLEtail#3}}% + \complexsecondstagestartTABLE[#1]} + +%D The optional third and fourth arguments define which table +%D head and tail to use. +%D +%D \starttyping +%D \definetabletemplate[test][|||][before][after] +%D \stoptyping +%D +%D This also means that one can define table heads and tails +%D by name! +%D +%D \starttyping +%D \starttablehead[before] +%D \HL \VL first \VL second \VL \SR \HL +%D \stoptablehead +%D \stoptyping +%D +%D Templates defined this way get protected names, that cannot +%D conflict with existing commands. +%D +%D \showsetup{definetabletemplate} +%D +%D The second half of the next macro prepares table +%D splitting. + +\def\insertTABLEhead + {\TABLEnoalign{\global\settrue \preventTABLEbreak \global\setfalse\someTABLEhead}% + \TABLEhead + \TABLEnoalign{\global\setfalse\preventTABLEbreak}} + +\def\insertTABLEtail + {\TABLEnoalign{\global\settrue \preventTABLEbreak \global\setfalse\someTABLEtail}% + \TABLEtail + \TABLEnoalign{\global\setfalse\preventTABLEbreak}} + +% \def\dorestartTABLE#1% +% {\gdef\restartTABLE{#1}% +% \restartTABLE +% \insertTABLEhead +% \ifsplittables \ifconditional \tablerepeattail +% \TABLEnoalign{\goodbreak}% +% \insertTABLEtail +% \TABLEnoalign{\goodbreak}% +% \fi \fi} + +\def\verysimpleTableHL + {\TABLEnoalign{\expandafter\normalTABLEfullrule\@@tiHLheight}} + +\def\dorestartTABLE#1% + {\gdef\restartTABLE{#1}% + \restartTABLE + \TABLEnoalign{\globalpushmacro\simpleTableHL\global\let\simpleTableHL\verysimpleTableHL}% + \insertTABLEhead + \ifsplittables \ifconditional \tablerepeattail + \TABLEnoalign{\goodbreak}% + \insertTABLEtail + \TABLEnoalign{\goodbreak}% + \fi \fi + \TABLEnoalign{\globalpopmacro\simpleTableHL}} + +\bgroup \catcode`|=\@@other \catcode`"=\@@other + +\gdef\complexsecondstagestartTABLE#1[#2]% brr nested mess + {\bgroup + \@@useotherbar + \@@useotherquote + \global\setfalse\someTABLEhead + \global\setfalse\someTABLEtail + \expanded{\doifinstringelse{|}{#2}} + {\xdef\restartTABLE{\noexpand\dorestartTABLE{\noexpand\thirdstagestartTABLE{#2}}}} + {\doifdefinedelse{\c!Table#2} + {\gdef\restartTABLE{\getvalue{\c!Table#2}}} + {\gdef\restartTABLE{\dorestartTABLE{\getvalue{#2}}}}}% + \egroup + \restartTABLE} + +\egroup + +%D The third stage involves a lot of (re)sets, which we will +%D explain later. + +%D The next definition is convenient and more in tune with +%D \CONTEXT. + +\let \everytable \EveryTable + +%D We immediately use this register: + +\appendtoks + \fixedspaces + \let\_\normalunderscore +\to \everytable + +%D Now we can start the table. + +\def\thirdstagestartTABLE#1% + {\global\setTABLEactiontrue + \setTABLEaction\TABLEunknown + \setTABLEforce\TABLEunknown + \setTABLEerror\TABLEunknown + \global\TABLEgraylinefalse + \global\TABLEgraydonefalse + \globalletempty\TABLEgrayline + \globalletempty\nextTABLEgrayline + \globalletempty\TABLEgraylineerror + \globalletempty\TABLEgraylinestatus + \resetVLvalues + \appendtoks\popouterbarandquote\to\EveryTable + \appendtoks\localTABLEsetup\to\EveryTable + \BeginTable[\ifsplittables u\else b\fi]% + \defineTABLEunits + \defineTABLEsteps + \defineTABLErules + \defineTABLEdivisions + \defineTABLEshorthands + \defineTABLEbackgrounds + \defineTABLEendings + \forgetall % added + \doifsomething{#1} + {\def\TABLEformat{#1}% + \getTABLEnofcolumns\TABLEformat + % more modern is to use catcode tables + \expandafter\BeginFormat\TABLEformat\EndFormat}} + +\def\finishTABLE + {\chuckTABLEautorow + \unskip\crcr + \EndTable + \global\intablefalse + \egroup} + +%D \macros +%D {starttables} +%D +%D Split tables are specified using the plural form of the +%D start and stop commands. +%D +%D \showsetup{starttables} +%D +%D For example: +%D +%D \starttyping +%D \starttables[|||] +%D \HL +%D \VL element \VL atom weight \VL\AR +%D \HL +%D \VL ....... \VL ........... \VL\AR +%D \VL ....... \VL ........... \VL\AR +%D \HL +%D \stoptables +%D \stoptyping + +\newbox\tablecontentbox + +\def\starttables + {\bgroup + \splittablestrue + \doifelse\@@tisplit\v!repeat + {\settrue \tablerepeathead\settrue \tablerepeattail} + {\setfalse\tablerepeathead\setfalse\tablerepeattail}% + \flushnotes + \setbox\tablecontentbox\vbox\bgroup + \forgetall + \global\TABLEinbreakfalse + \firststagestartTABLE} + +% \def\stoptables +% {\ifconditional\tablerepeattail\else\insertTABLEtail\fi +% \finishTABLE +% \egroup +% \dosplittablebox\tablecontentbox +% \flushnotes +% \egroup} + +\def\stoptables + {\chuckTABLEautorow % AM: before the tail, else noalign problem + \ifconditional\tablerepeattail\else\insertTABLEtail\fi + \finishTABLE + \egroup +\dontcomplain + \dosplittablebox\tablecontentbox + \flushnotes + \egroup} + +\newdimen\TABLEcaptionheight % obsolete + +\def\dosplittablebox#1% + {\resettsplit + \def\tsplitminimumfreelines{2}% + \def\tsplitminimumfreespace{\TABLEcaptionheight}% + \setbox\tsplitcontent\box#1% + \ifconditional\tablerepeathead \ifconditional\someTABLEhead + \setbox\tsplithead\vsplit\tsplitcontent to \lineheight + \setbox\tsplithead\vbox{\unvbox\tsplithead}% + \fi \fi + \ifconditional\tablerepeattail \ifconditional\someTABLEtail + \setbox\tsplittail\vsplit\tsplitcontent to \lineheight + \setbox\tsplittail\vbox{\unvbox\tsplittail}% + \fi \fi + \ifinsidefloat\else + \def\tsplitbeforeresult{\startbaselinecorrection}% + \def\tsplitafterresult {\stopbaselinecorrection}% + \fi + \handletsplit} + +%D When the table in the previous example is split across +%D pages, only the first gets a head. We could have said +%D something like: +%D +%D \starttyping +%D \starttablekop +%D \HL +%D \VL element \VL atom weight \VL\AR +%D \HL +%D \stoptablekop +%D +%D \starttablestaart +%D \HL +%D \stoptablestaart +%D +%D \starttables[|||] +%D \VL ....... \VL ........... \VL\AR +%D \VL ....... \VL ........... \VL\AR +%D \stoptables +%D \stoptyping +%D +%D This time each split table gets a head line and ends with +%D a rule. Keep in mind that such heads also apply to the +%D unbroken ones and should be defined local (grouped) if +%D needed. The rather complicated definition below is due to +%D the fact that the stopcondition is interface language +%D dependant. + +\let\@@TABLEhead\empty \def\TABLEhead{\@@TABLEhead} +\let\@@TABLEtail\empty \def\TABLEtail{\@@TABLEtail} + +\letvalue{\e!start\v!tablehead}=\undefined +\letvalue{\e!stop \v!tablehead}=\undefined +\letvalue{\e!start\v!tabletail}=\undefined +\letvalue{\e!stop \v!tabletail}=\undefined + +\expanded + {\def\csname\e!start\v!tablehead\endcsname##1\csname\e!stop\v!tablehead\endcsname% + {\noexpand\setTABLEhead##1\noexpand\end}} + +\expanded + {\def\csname\e!start\v!tabletail\endcsname##1\csname\e!stop\v!tabletail\endcsname% + {\noexpand\setTABLEtail##1\noexpand\end}} + +%D The second argument is a dummy one, by scanning for it, we +%D get rid of interfering spaces. + +\def\setTABLEhead{\dodoubleempty\dosetTABLEhead} +\def\setTABLEtail{\dodoubleempty\dosetTABLEtail} + +\newconditional\preventTABLEbreak +\newconditional\someTABLEhead + +\def\dosetTABLEhead[#1][#2]#3\end{\setvalue{@@TABLEhead#1}{\TABLEnoalign{\global\settrue\someTABLEhead}#3}} +\def\dosetTABLEtail[#1][#2]#3\end{\setvalue{@@TABLEtail#1}{\TABLEnoalign{\global\settrue\someTABLEtail}#3}} + +%D Redudant \type{\HL}'s are removed automatically, so +%D mid||lines can be used without problems. + +%D We need an alternative for the normal complex or simple +%D commands, because assignments in these system commands +%D conflict with \type{\noalign}. This alternative is about +%D as efficient as possible. + +\def\complexorsimpleTable#1#2% + {\csname\if[\noexpand#2\s!complex\else\s!simple\fi\c!Table#1\endcsname#2} + +%D The next one is used in \type{\VL} cum suis and honours +%D the next grouping. + +\def\docomplexorsimpleTable#1#2% + {\ifx\next\bgroup\@EA#2\else\@EA\dodocomplexorsimpleTable\@EA#1\@EA#2\fi} + +\def\dodocomplexorsimpleTable#1#2#3% + {\if[\noexpand#3\@EA#1\else\@EA#2\fi#3} + +%D The order of the next macros is more or less random. First +%D we implement error recovery. Errors are reported to the +%D screen and log file as well as visualized in the table in +%D teletype. + +\def\handleTABLEerror + {\ifTABLEgrayline \else + \ifnum\TABLEerror=\TABLEunknown \else + \setTABLEaction\TABLEunknown + \globalletempty\checkTABLEautorow + \globalletempty\chuckTABLEautorow + \fi + \ifcase\TABLEerror + % no error + \or + % \TABLEmissingrow + \tttf [missing row]% + \writestatus\m!TABLE{missing row}% + \SR + \or + % \TABLEmissingcolumn + \fillTABLEcolumns + \tttf [missing column]% + \writestatus\m!TABLE{missing column}% + \SR + \or + % \TABLEspanoverflow + \fillTABLEcolumns + \tttf [columnspan too large]% + \writestatus\m!TABLE{columnspan too large}% + \SR + \or + % \TABLEdivisionoverflow + \fillTABLEcolumns + \tttf [division line too long]% + \writestatus\m!TABLE{division line too long}% + \SR + \fi + \fi + \ifnum\TABLEerror=\TABLEunknown \else + \finishTABLErow + \fi} + +\def\finishTABLErow + {\crcr + \TABLEnoalign + {\nobreak + \setTABLEaction\TABLEunknown + \setTABLEerror\TABLEunknown + \globalletempty\checkTABLEautorow + \globalletempty\chuckTABLEautorow + \global\currentTABLEcolumn\zerocount}} + +\def\fillTABLEcolumns + {\ifnum\currentTABLEcolumn>\maxTABLEcolumn \else + \global\advance\currentTABLEcolumn \plusone + \normalTABLEquote + \expandafter\fillTABLEcolumns + \fi} + +%D Next we enter the more complicated area of column and row +%D switching. I won't go into much detail from now on, but just +%D mention the general principles. +%D +%D \startitemize[3*ruim] +%D \sym{\type{\SR}} end a separate row (between rules) +%D \sym{\type{\FR}} end a first row (after a rule) +%D \sym{\type{\MR}} end a mid row (between text lines) +%D \sym{\type{\LR}} end a last row (before a rule) +%D \stopitemize +%D +%D and best of all: +%D +%D \startitemize[continue] +%D \sym{\type{\AR}} end a row with automatic spacing +%D \stopitemize +%D +%D As far as possible, we report confusing situations. In +%D most cases one can use \type{\AR}, which transfigurates +%D itself into one of the other types. +%D +%D \starttyping +%D \starttable[||] +%D \HL +%D \VL a separate row \VL\SR +%D \HL +%D \VL a first row \VL\FR +%D \VL a mid row \VL\MR +%D \VL a last row \VL\LR +%D \HL +%D \stoptable +%D \stoptyping +%D +%D In this example we could have used \type{\AR} without +%D problems. +%D +%D Color or gray scale backgrounds precede the content. They +%D are passed over horizontal (division) lines when needed. +%D Errors in the color template are traced elsewhere. Here we +%D only check for inconsistent spacing. Due to the way \TEX\ +%D handles alignments, we cannot automate spacing for colored +%D rows and columns. + +\chardef\TABLErowzero=0 + +\def\checkTABLErow#1% pure for message purposes + {\unskip % added + \ifTABLEgraydone + \defconvertedargument\asciia{#1}% + \defconvertedcommand \asciib\TABLEendBCL + \ifx\asciia\asciib \else + \writestatus\m!TABLE{confusing \asciia\space and \asciib}% + \gdef\TABLEgraylineerror% + {\globalletempty\TABLEgraylineerror + [\asciia\unskip<->\asciib\unskip]}% + \fi + \global\TABLEgraydonefalse + \fi} + +\def\defineTABLEendings + {\let\SR\TableSR + \let\FR\TableFR + \let\MR\TableMR + \let\LR\TableLR + \let\AR\TableAR} + +\def\TableSR + {\ifTABLEgrayline \else + \ifnum\TABLEaction=\TABLEfirstrow + \writestatus\m!TABLE{change \string\SR\space into \string\MR/\string\LR}% + \else\ifnum\TABLEaction=\TABLEmidrow + \writestatus\m!TABLE{change \string\SR\space into \string\MR/\string\LR}% + \else\ifnum\TABLEaction=\TABLEmidrow + \writestatus\m!TABLE{change \string\SR\space into \string\MR/\string\LR}% + \fi\fi\fi + \fi + \checkTABLErow\SR + \endTABLErow\TABLEseparaterow\TABLErowfactor\TABLErowfactor} + +\def\TableFR + {\ifTABLEgrayline \else + \ifnum\TABLEaction=\TABLEmidrow + \writestatus\m!TABLE{change \string\FR\space into \string\MR/\string\LR}% + \else\ifnum\TABLEaction=\TABLElastrow + \writestatus\m!TABLE{change \string\FR\space into \string\MR/\string\LR}% + \fi\fi + \fi + \checkTABLErow\FR + \endTABLErow\TABLEfirstrow\TABLErowfactor\TABLErowzero} + +\def\TableMR + {\ifTABLEgrayline \else + \ifnum\TABLEaction=\TABLErule + \writestatus\m!TABLE{change \string\MR\space into \string\FR/\string\SR}% + \else\ifnum\TABLEaction=\TABLElastrow + \writestatus\m!TABLE{change \string\MR\space into \string\FR}% + \fi\fi + \fi + \checkTABLErow\MR + \endTABLErow\TABLEmidrow00} + +\def\TableLR + {\ifTABLEgrayline \else + \ifnum\TABLEaction=\TABLErule + \writestatus\m!TABLE{change \string\LR\space into \string\FR/\string\SR}% + \fi + \fi + \checkTABLErow\LR + \endTABLErow\TABLElastrow\TABLErowzero\TABLErowfactor} + +%D \macros +%D {ifcheckTABLEcolums} +%D +%D +%D The next macros handle the actual row ending. This macro +%D also take care of space corrections due to table splitting +%D when \type{\MR} and collegues are used. When tracing is +%D enabled, the corrections as well as the values used to +%D determine the available space are shown (in color). By default +%D checking is off. + +\newif\ifcheckTABLEcolumns + +\let\beforeTABLEline\empty +\let\afterTABLEline \empty + +\def\doendTABLErow#1#2#3% + {\handleTABLEbreak#2#3% + \beforeTABLEline + \ifcase#1\relax + % unknown + \or + \endofTABLEline[blue][\SR->\SR]\TABLErowfactor\TABLErowfactor + \or + \endofTABLEline[red][\FR->\FR]\TABLErowfactor\TABLErowzero + \or + \ifnum\TABLEforce=\TABLEforcelastrow + \endofTABLEline[red][\MR->\LR]\TABLErowzero\TABLErowfactor + \else\ifnum\TABLEforce=\TABLEforcefirstrow + \endofTABLEline[red][\MR->\FR]\TABLErowfactor\TABLErowzero + \else + \endofTABLEline[green][\MR->\MR]\TABLErowzero\TABLErowzero + \fi\fi + \or + \endofTABLEline[red][\LR->\LR]\TABLErowzero\TABLErowfactor + \fi + \TABLEnoalign + {\setTABLEforce\TABLEunknown + \global\currentTABLEcolumn\zerocount}% + \afterTABLEline} + +\def\endTABLErow#1#2#3% + {\setTABLEaction#1% + \ifTABLEgrayline + \finishTABLErow + \else + \ifnum\currentTABLEcolumn>\maxTABLEcolumn + \doendTABLErow{#1}{#2}{#3}% + \else\ifcheckTABLEcolumns + \setTABLEerror\TABLEmissingcolumn + \handleTABLEerror + \else + \doendTABLErow{#1}{#2}{#3}% + \fi\fi + \fi} + +%D Handling \type{\AR} is postponed till the next row. The +%D check takes care of the first and mid rows, the chuck macro +%D |<|how about that name|>| handles the last row. + +\def\TableAR + {\ifTABLEgraydone + \globalletempty\checkTABLEautorow + \globalletempty\chuckTABLEautorow + \global\TABLEgraydonefalse + \TABLEendBCL + \else + \globallet\checkTABLEautorow\docheckTABLEautorow + \globallet\chuckTABLEautorow\dochuckTABLEautorow + \fi} + +\let\checkTABLEautorow\empty +\let\chuckTABLEautorow\empty + +\def\docheckTABLEautorow + {\globallet\checkTABLEautorow\empty + \ifnum\TABLEaction=\TABLErule \FR + \else\ifnum\TABLEaction=\TABLEunknown \FR + \else \MR + \fi\fi} + +\def\dochuckTABLEautorow + {\globalletempty\checkTABLEautorow + \globalletempty\chuckTABLEautorow + \ifnum\TABLEaction=\TABLErule \SR + \else\ifnum\TABLEaction=\TABLEunknown \SR + \else \LR + \fi\fi} + +%D When a table is split, we also add a tail and when present +%D we repeat the table head. + +\def\handleTABLEbreak#1#2% + {\globalletempty\beforeTABLEline + \gdef\afterTABLEline{\TABLEnoalign{\ifconditional\preventTABLEbreak\nobreak\else\goodbreak\fi}}} + +%D When tables are split, the spacing before and after a +%D horizontal rule is corrected according to what we expect. + +\def\endofTABLEline[#1][#2->#3]#4#5% + {\ifx#2#3\else + \writestatus\m!TABLE{\string#2\space changed into \string#3}% + \fi + \iftracetables + \bgroup + \tttf\space + \ifnum\TABLEerror=\TABLEunknown + \ifx#2#3\else\string#2->\fi + \else + ->% + \fi + \color[#1]{\string#3}% + \ifx\TABLEgraylineerror\empty + \space\TABLEgraylinestatus + \else + \space\TABLEgraylineerror + \fi + \egroup + \else\ifx\TABLEgraylineerror\empty \else + % \bgroup + % \tttf\space\TABLEgraylineerror + % \egroup + \fi\fi + \globalletempty\TABLEgraylinestatus + \globalletempty\TABLEgraylineerror + \expandafter\normalTABLElineformat#4#5\crcr % \crcr nodig ? + \TABLEnoalign{\nobreak\global\setTABLEactiontrue}} + +%D In order to prevent (as good as possible) alignment overflow +%D and therefore \TEX\ error messages, we check the maximum +%D number of columns. We keep track of the current column and +%D maximum column by means of two \COUNTERS. Keep in mind that +%D the number of \type{|}'s and \type{\VL}'s or alike is always +%D one more than the number of columns. + +\newcount\currentTABLEcolumn +\newcount\maxTABLEcolumn + +%D While defining this macro we change the \CATCODE\ of +%D \type{|}. When counting the bars, we use a non active +%D representation of the bar, simply because we cannot be sure +%D if the bar is active or not.\footnote{Normally it is, but +%D \TABLE\ changes the catcode when needed.} + +\bgroup + \catcode`\|=\@@other \gdef\@@otherbar {|} + \catcode`\"=\@@other \gdef\@@otherquote {"} + \catcode`\|=\@@active \gdef\@@useotherbar {\let|\@@otherbar} + \catcode`\"=\@@active \gdef\@@useotherquote{\let"\@@otherquote} +\egroup + +\bgroup \catcode`\|=\@@other + +\gdef\getTABLEnofcolumns#1% + {\bgroup + \cleanupfeatures % needed ! + \@@useotherbar + \@@useotherquote + \expanded{\defconvertedargument\noexpand\ascii{#1}}% + \@EA\doglobal\@EA\counttoken\@EA|\@EA\in\ascii\to\maxTABLEcolumn + \global\advance\maxTABLEcolumn \minusone + % in case of & counting, divide by 2 + \egroup} + +\egroup + +\def\!ttDoHalign + {\edef\restoretablelineskips + {\baselineskip \the\baselineskip + \lineskiplimit\the\lineskiplimit + \lineskip \the\lineskip + \tabskip \the\tabskip}% + \baselineskip \zeropoint + \lineskiplimit\zeropoint + \lineskip \zeropoint + \tabskip \zeropoint + % does not work in normal tex + % \expanded{\getTABLEnofcolumns{\the\!taPreamble}}% added + \halign \the\!taTableSpread \bgroup + \span\the\!taPreamble + \ifx \!tfRowOfWidths \empty \else \!tfRowOfWidths \cr \fi} + +%D \startitemize[3*ruim] +%D \sym{\type{\VL}} a vertical line +%D \sym{\type{\VC}} a vertical colored line +%D \sym{\type{\HL}} a horizontal line +%D \sym{\type{\HC}} a horizontal colored line +%D \stopitemize + +% \def\defineTABLErules +% {\let\VL\TableVL +% \let\VC\TableVC +% \let\HL\TableHL +% \let\HC\TableHC} + +\def\defineTABLErules + {\let\VL\TableVL + \let\VC\TableVC + \let\HL\TableHL + \let\HC\TableHC + \let\VS\TableVS + \let\VD\TableVD + \let\VT\TableVT + \let\VN\TableVN} + +\def\TableVL + {\checkTABLEautorow + \nextTABLEgrayline + \ifnum\currentTABLEcolumn>\maxTABLEcolumn + \setTABLEerror\TABLEmissingrow + \handleTABLEerror + \else + \global\advance\currentTABLEcolumn \plusone + \expandafter\doTableVL + \fi} + +\def\doTableVL + {\futurelet\next\dodoTableVL} + +\def\dodoTableVL + {\docomplexorsimpleTable\complexTableVL\simpleTableVL} + +\def\complexTableVL[#1]% + {\scratchcounter=0#1% + \multiply\scratchcounter \@@tiVLwidth + \setxvalue{wVL\the\currentTABLEcolumn}{\the\scratchcounter}% + \simpleTableVL} + +\def\simpleTableVL + {\doifundefined{wVL\the\currentTABLEcolumn}% + {\setgvalue{wVL\the\currentTABLEcolumn}{\@@tiVLwidth}}% + \gdef\TABLEbeforebar + {\getvalue{bVL\the\currentTABLEcolumn}% + \letgvalueempty{bVL\the\currentTABLEcolumn}}% + \gdef\TABLEafterbar + {\getvalue{eVL\the\currentTABLEcolumn}% + \letgvalueempty{eVL\the\currentTABLEcolumn}}% + \edef\@@tiVLwidth{\getvalue{wVL\the\currentTABLEcolumn}}% + \expanded{\normalTABLEcomplexbar\@@tiVLwidth\space}}% \relax breaks \use + +% \starttable[|||] +% \HL +% \VL test \VS test \VL \FR +% \VL test \VD test \VL \MR +% \VL test \VT test \VL \LR +% \HL +% \stoptable + +\def\TableVS {\VN1} +\def\TableVD {\VN2} +\def\TableVT {\VN3} +\def\TableVN#1{\gdef\@VLn{#1}\VL} + +\def\resetVLvalues + {\dostepwiserecurse\zerocount\maxTABLEcolumn\plusone + {\setgvalue{wVL\recurselevel}{\@@tiVLwidth}% + \letgvalueempty{bVL\recurselevel}% + \letgvalueempty{eVL\recurselevel}}% + \global\currentTABLEcolumn\zerocount} + +\def\TableVC + {\checkTABLEautorow + \nextTABLEgrayline + \ifnum\currentTABLEcolumn>\maxTABLEcolumn + \setTABLEerror\TABLEmissingrow + \handleTABLEerror + \else + \global\advance\currentTABLEcolumn \plusone + \expandafter\doTableVC + \fi} + +\def\doTableVC + {\futurelet\next\dodoTableVC} + +\def\dodoTableVC + {\docomplexorsimpleTable\complexTableVC\simpleTableVC} + +\def\complexTableVC[#1]% + {\global\setvalue{bVC\the\currentTABLEcolumn}{\localstartcolor[#1]}% + \global\setvalue{eVC\the\currentTABLEcolumn}{\localstopcolor}% + \simpleTableVC} + +\def\simpleTableVC + {\global\setvalue{bVL\the\currentTABLEcolumn}% + {\getvalue{bVC\the\currentTABLEcolumn}}% + \global\setvalue{eVL\the\currentTABLEcolumn}% + {\getvalue{eVC\the\currentTABLEcolumn}}% + \doTableVL} + +\def\TableHL + {\ifnum\currentTABLEcolumn>\maxTABLEcolumn + \chuckTABLEautorow + \else\ifnum\currentTABLEcolumn=\zerocount + %\chuckTABLEautorow + \TABLEnoalign + {\globalletempty\checkTABLEautorow + \globalletempty\chuckTABLEautorow}% + \else + \setTABLEerror\TABLEmissingcolumn + \handleTABLEerror + \fi\fi + \complexorsimpleTable{HL}} + +\def\complexTableHL[#1]% + {\TABLEnoalign + {\scratchcounter0#1% + \multiply\scratchcounter \@@tiHLheight + \edef\@@tiHLheight{\the\scratchcounter}% + \simpleTableHL}} + +\def\simpleTableHL + {\TABLEnoalign + {\nobreak + \ifnum\TABLEaction=\TABLErule + \writestatus\m!TABLE{skipping \string\HL}% \statusmessage + \else + \ifnum\TABLEaction=\TABLEmidrow + \writestatus\m!TABLE{change \string\MR\space into \string\LR/\string\SR}% + \else\ifnum\TABLEaction=\TABLEfirstrow + \writestatus\m!TABLE{change \string\MR\space into \string\SR}% + \fi\fi + \startHLcommand + \expandafter\normalTABLEfullrule\@@tiHLheight + \stopHLcommand + \globalletempty\startHLcommand + \globalletempty\stopHLcommand + \accountTABLElinewidth + \fi + \setTABLEaction\TABLErule + \nobreak}} + +\let\startHLcommand\empty +\let\stopHLcommand \empty + +\def\TableHC + {\complexorsimpleTable{HC}} + +\def\complexTableHC[#1]% + {\TABLEnoalign + {\gdef\startHCcommand{\localstartcolor[#1]}% + \gdef\stopHCcommand {\localstopcolor}}% + \simpleTableHC} + +\def\simpleTableHC + {\TABLEnoalign + {\globallet\startHLcommand\startHCcommand + \globallet\stopHLcommand \stopHCcommand}% + \HL} + +%D \startitemize[3*ruim] +%D \sym{\type{\NL}} a vertical skip +%D \sym{\type{\NR}} goto the next row +%D \sym{\type{\NC}} goto the next column +%D \sym{\type{\FC}} a first column +%D \sym{\type{\MC}} a mid column +%D \sym{\type{\LC}} a last column +%D \stopitemize + +% n+1 uitleggen + +\def\defineTABLEsteps + {\let\NL\TableNL + \let\NR\TableNR + \let\NC\TableNC + \let\FC\TableNC + \let\MC\TableNC + \let\LC\TableNC} + +\def\TableNL + {\complexorsimpleTable{NL}} + +\def\complexTableNL[#1]% + {\TABLEnoalign + {\edef\@@tiNL{#1}% + \simpleTableNL}}% + +\def\simpleTableNL + {\TABLEnoalign + {\nobreak + \setbox0\vbox{\blank[\@@tiNL]}% + \vskip\ht0 + \nobreak}} + +\def\TableNR + {\ifnum\currentTABLEcolumn>\maxTABLEcolumn + \global\currentTABLEcolumn\zerocount + \normalTABLElineending + \else + \setTABLEerror\TABLEmissingcolumn + \handleTABLEerror + \fi + \TABLEnoalign + {\nobreak + \setTABLEaction\TABLEunknown}} + +\def\TableNC + {\checkTABLEautorow + \nextTABLEgrayline + \ifnum\currentTABLEcolumn>\maxTABLEcolumn + \setTABLEerror\TABLEmissingrow + \handleTABLEerror + \else + \global\advance\currentTABLEcolumn \plusone + \normalTABLEquote + \fi} + +% \bgroup +% \catcode`\|=\@@active +% \catcode`\"=\@@active +% \gdef\redefinetablebarandquote +% {\def|{\VL}% % \normalTABLEsimplebar +% \def\|##1{\VL[##1]}% % \normalTABLEcomplexbar +% \def"{\NC}} % \normalTABLEquote +% \egroup + +\let\redefinetablebarandquote\relax + +%D \startitemize[3*ruim] +%D \sym{\type{\DL}} +%D \sym{\type{\DV}} (\type{\VD}) +%D \sym{\type{\DC}} +%D \sym{\type{\DR}} +%D \stopitemize + +\newif\ifTABLEdivision + +% \def\defineTABLEdivisions +% {\global\TABLEdivisionfalse % in start +% \let\DL\TableDL +% \let\DC\TableDC +% \let\DV\TableDV +% \let\VD\TableDV +% \let\DR\TableDR} + +\def\defineTABLEdivisions + {\global\TABLEdivisionfalse % in start + \let\DL\TableDL + \let\DC\TableDC + \let\DV\TableDV + \let\DR\TableDR} + +\def\checkTABLEdivision + {\ifTABLEdivision \else + \chuckTABLEautorow + \global\currentTABLEcolumn\zerocount + \global\TABLEdivisiontrue + \fi} + +\def\TableDL + {\checkTABLEdivision + \complexorsimpleTable{DL}} + +\def\simpleTableDL + {\complexTableDL[1]} + +\def\complexTableDL[#1]% + {\ifnum\TABLEaction=\TABLErule + \writestatus\m!TABLE{skipping \string\DL}% + \else + \ifnum\TABLEaction=\TABLEmidrow + \writestatus\m!TABLE{change \string\MR\space into \string\LR/\string\SR}% + \else\ifnum\TABLEaction=\TABLEfirstrow + \writestatus\m!TABLE{change \string\MR\space into \string\SR}% + \fi\fi + \setTABLEaction=\TABLEunknown + \ifnum\currentTABLEcolumn>\maxTABLEcolumn + \setTABLEerror\TABLEmissingrow + \handleTABLEerror + \fi + %\startHLcommand + \ifnum#1=\plusone + \global\advance\currentTABLEcolumn \plustwo + \let\next\normalTABLEsinglerule + \else + \ifnum#1<\maxTABLEcolumn + \global\advance\currentTABLEcolumn \plusone + \def\next{\normalTABLEmultirule{#1}}% + \else + \setTABLEerror\TABLEdivisionoverflow + \let\next\handleTABLEerror + \fi + \fi + \next + %\stopHLcommand + %\globalletempty\startHLcommand + %\globalletempty\stopHLcommand + \fi} + +\def\TableDV + {\TableDCV\normalTABLEsimplebar} + +\def\TableDC + {\TableDCV\normalTABLEquote} + +\def\TableDCV#1% + {\checkTABLEdivision + \checkTABLEautorow + \ifnum\currentTABLEcolumn>\maxTABLEcolumn + \setTABLEerror\TABLEmissingrow + \handleTABLEerror + \else + \global\advance\currentTABLEcolumn \plusone + #1% + \fi} + +\def\TableDR + {\ifnum\currentTABLEcolumn<\maxTABLEcolumn % silent recovery + %\setTABLEerror\TABLEmissingcolumn % some day warning + %\handleTABLEerror + \finishTABLErow + \else + \global\currentTABLEcolumn\zerocount % nog check + \normalTABLElineending + \fi + \TABLEnoalign + {\nobreak + \global\TABLEdivisionfalse + \accountTABLElinewidth % temporary solution + \setTABLEaction\TABLErule}} + +\def\accountTABLElinewidth + {\scratchdimen\LineThicknessUnit} + +%D \startitemize[3*ruim] +%D \sym{\type{\BC}} +%D \sym{\type{\BR}} +%D \sym{\type{\BACKGROUND}} +%D \sym{\type{\CL}} +%D \sym{\type{\RL}} +%D \sym{\type{\BL}} +%D \sym{\type{\RASTER}} +%D \sym{\type{\COLOR}} +%D \stopitemize + +% definieer: \BC \BL +% herhaal: \BR +% definieer: \CL \RL (eerste \CL[green] = hele row! / \CL[1,green]) +% dus: \CL en \RL mix tussen \HL en \BL + +\def\defineTABLEbackgrounds + {\let\BC \TableBC + \let\BL \TableBL + \let\BR \TableBR + \let\BACKGROUND\TableBR + \let\CL \TableCL + \let\RL \TableRL + \let\COLOR \TableCOLOR + \let\RASTER \TableRASTER + \globallet\lastTABLEc\@@tibackgroundcolor + \globallet\lastTABLEr\@@tibackgroundscreen + \doifinsetelse\@@tibackground{c,color} % \v!color + {\global\chardef\TABLEcr\plusone} + {\global\chardef\TABLEcr\plustwo}} + +\def\TableBC + {\ifTABLEgrayline + \normalTABLEquote + \else + \TABLEnoalign\bgroup + \globallet\nextTABLEgrayline\executeTABLEgrayline + \globalletempty\TABLEgrayline % new + \let\BL\doTableBL + \let\BC\doTableBC + \expandafter\doTableBC + \fi} + +\def\doTableBC + {\addtoTABLEgrayline{\BC}% + \gobbleTableBCL} + +\def\TableBL + {\TABLEnoalign\bgroup + \globallet\nextTABLEgrayline\executeTABLEgrayline + \globalletempty\TABLEgrayline % new + \let\BL\doTableBL + \let\CL\doTableCL + \let\RL\doTableRL + \let\BC\doTableBC + \doTableBL} + +\def\doTableBL + {\complexorsimpleTable{BL}} + +\def\simpleTableBL + {\complexTableBL[,]} + +\def\complexTableBL[#1]% + {\analyzeTABLEcr[#1]% + \handleTABLEcr} + +\def\TableBR#1% + {\TABLEnoalign + {\globallet\nextTABLEgrayline\executeTABLEgrayline + \checkTABLEgrayline#1\BR + \global\TABLEgraylinetrue}} + +\def\analyzeTABLEcr[#1]% + {\doanalyzeTABLEcr[#1,,]} + +\def\doanalyzeTABLEcr[#1,#2,#3]% + {\doifnumberelse{#1x} % Is the x still needed here? + {\dodoanalyzeTABLEcr[#1,#2,#3]} + {\dodoanalyzeTABLEcr[1,#1,#2]}} + +\def\dodoanalyzeTABLEcr[#1,#2,#3]% + {\global\chardef\TABLEn#1\relax + \processaction + [#2] + [ c=>\global\chardef\TABLEcr1,% + color=>\global\chardef\TABLEcr1,% + r=>\global\chardef\TABLEcr2,% + raster=>\global\chardef\TABLEcr2]% + \ifcase\TABLEcr \or + \doifsomething{#3}{\xdef\lastTABLEc{#3}}% + \or + \doifsomething{#3}{\xdef\lastTABLEr{#3}}% + \fi} + +\def\handleTABLEcr + {\relax % else funny side effect + \ifcase\TABLEcr + % Can't happen! + \or + \addtoTABLEgrayline{\complexTableCOLOR[\the\TABLEn,\lastTABLEc]}% + \else + \addtoTABLEgrayline{\complexTableRASTER[\the\TABLEn,\lastTABLEr]}% + \fi + \gobbleTableBCL} + +\def\analyzeTABLEcrl#1[#2]% + {\doanalyzeTABLEcrl#1[#2,,]} + +\def\doanalyzeTABLEcrl#1[#2,#3,#4]% + {\doifnumberelse{#2x} % x ???????????????????? + {\dodoanalyzeTABLEcr[#2,#1,#3]} + {\dodoanalyzeTABLEcr[\ifTABLEgrayline1\else\maxTABLEcolumn\fi,#1,#2]}} + +\def\TableCL + {\TABLEnoalign\bgroup + \globallet\nextTABLEgrayline\executeTABLEgrayline + \globalletempty\TABLEgrayline % new + \let\BL\doTableBL + \let\CL\doTableCL + \let\RL\doTableRL + \let\BC\doTableBC + \doTableCL} + +\def\doTableCL + {\complexorsimpleTable{CL}} + +\def\simpleTableCL% nog eens \'e\'en lijn van maken + {\BL[\the\maxTABLEcolumn,c,\lastTABLEc]} + +\def\complexTableCL[#1]% + {\analyzeTABLEcrl{c}[#1]% + \handleTABLEcr} + +\def\TableRL + {\TABLEnoalign\bgroup + \globallet\nextTABLEgrayline\executeTABLEgrayline + \globalletempty\TABLEgrayline % new + \let\BL\doTableBL + \let\CL\doTableCL + \let\RL\doTableRL + \let\BC\doTableBC + \doTableRL} + +\def\doTableRL + {\complexorsimpleTable{RL}} + +\def\simpleTableRL + {\BL[\the\maxTABLEcolumn,r,\lastTABLEr]} + +\def\complexTableRL[#1]% + {\analyzeTABLEcrl{r}[#1]% + \handleTABLEcr} + +\def\checkTABLEgrayline#1#2% + {\!!doneatrue + \ifx#1\AR + \!!doneafalse + \else\ifx#1\SR\else\ifx#1\FR\else\ifx#1\MR\else\ifx#1\LR\else + \!!doneafalse + \fi\fi\fi\fi\fi + \if!!donea + \gdef\TABLEgraylinestatus + {[\string#1]}% + \gdef\TABLEendBCL + {#1}% + \else + \gdef\TABLEgraylineerror + {[\string#2\string#1->\string#2\string\SR]}% + \gdef\TABLEendBCL + {\SR}% + \fi} + +\def\endTABLErowGL#1#2#3% + {\ifcase#1\relax + % unknown + \or + \doPreTableGL\TABLErowfactor\TABLErowfactor + \or + \doPreTableGL\TABLErowfactor\TABLErowzero + \or + \ifnum\TABLEforce=\TABLEforcelastrow + \doPreTableGL\TABLErowzero\TABLErowfactor + \else\ifnum\TABLEforce=\TABLEforcefirstrow + \doPreTableGL\TABLErowfactor\TABLErowzero + \else + \doPreTableGL\TABLErowzero\TABLErowzero + \fi\fi + \or + \doPreTableGL\TABLErowzero\TABLErowfactor + \fi} + +\def\doPreTableGL#1#2% betere namen + {\xdef\OldLineThicknessFactor{\the\LineThicknessFactor}% + \xdef\OldLineThicknessUnit{\the\LineThicknessUnit}% + \global\LineThicknessFactor\plusone + \setbox0\hbox{\AugmentedTableStrut{#1}{#2}}% + \getboxheight\dimen0\of\box0\relax + \xdef\TABLEgraylineHeight{\the\dimen0}% + \global\LineThicknessUnit\TABLEgraylineHeight} + +\def\doPostTableGL + {\global\LineThicknessFactor\OldLineThicknessFactor + \global\LineThicknessUnit \OldLineThicknessUnit} + +% kan simpeler + +\def\docomplexTableCOLOR[#1]% + {\dodocomplexTableGL\localstartcolor \localstopcolor [#1,\lastTABLEc,,]} + +\gdef\docomplexTableRASTER[#1]% + {\dodocomplexTableGL\localstartraster\localstopraster[#1,\lastTABLEr,,]} + +\def\dodocomplexTableGL#1#2[#3,#4,#5,#6]% + {\doifelsenothing{#4}{#1[#5]}{#1[#4]}% + \doPreTableGL\TABLEendofrowheight\TABLEendofrowdepth + \ifnum#3=\plusone % else conflict with \omit in \= + \let\next\normalTABLEsinglerule + \else + \def\next{\normalTABLEmultirule{#3}}% + \fi + \next + \doPostTableGL + #2} + +\def\TableBACKGROUND + {\TableBR} + +\def\simpleTableRASTER #1{\docomplexTableRASTER[1]#1} +\def\complexTableRASTER[#1]{\docomplexTableRASTER[#1]} +\def\simpleTableCOLOR {\docomplexTableCOLOR [1]} +\def\complexTableCOLOR [#1]{\docomplexTableCOLOR [#1]} + +\def\TableRASTER{\complexorsimpleTable{RASTER}} +\def\TableCOLOR {\complexorsimpleTable{COLOR}} + +\def\addtoTABLEgrayline#1% + {\TABLEgraytoks\expandafter{\TABLEgrayline}% + \xdef\TABLEgrayline{\the\TABLEgraytoks\noexpand#1}} + +\def\setTableBCL#1#2% + {\ifx#1#2% + \gdef\TABLEgraylinestatus{[\string#1]}% + \gdef\TABLEendBCL{#1}% + \addtoTABLEgrayline{#1}% + \else + \gdef\TABLEgraylineerror{[\string#1->\string#2]}% + \gdef\TABLEendBCL{#2}% + \addtoTABLEgrayline{#2}% + \fi} + +\def\gobbleTableBCL#1% + {\ifx#1\BC \let\next\doTableBC \else + \ifx#1\BL \let\next\doTableBL \else + \ifx#1\SR \setTableBCL\SR\SR \let\next\egroup \else + \ifx#1\FR \setTableBCL\FR\FR \let\next\egroup \else + \ifx#1\MR \setTableBCL\MR\MR \let\next\egroup \else + \ifx#1\LR \setTableBCL\LR\LR \let\next\egroup \else + \setTableBCL #1\SR \let\next\egroup + \fi\fi\fi\fi\fi\fi + \next} + +\def\executeTABLEgrayline + {\TABLEnoalign + {\def\BC + {\advance\currentTABLEcolumn \plusone}% + \def\dodocomplexTableGL##1##2[##3,##4,##5,##6]% + {\BC\advance\currentTABLEcolumn ##3 }% + \let\endTABLErow\endTABLEgrayrow + \currentTABLEcolumn\zerocount + \TABLEgrayline\TABLEendBCL % determine n of columns and height + \advance\currentTABLEcolumn \minusone + \ifnum\currentTABLEcolumn>\maxTABLEcolumn + % error message too long line + \globalletempty\TABLEgrayline + \else + % \message{n of color columns: \the\currentTABLEcolumn}\wait + \global\TABLEgraylinetrue % vanaf hier nog checken + \fi + \global\currentTABLEcolumn\zerocount}% + \unskip\TABLEgrayline\TABLEendBCL + \TABLEnoalign + {\nobreak + \vskip-\TABLEgraylineHeight + \nobreak + \global\setTABLEactiontrue + \global\currentTABLEcolumn\zerocount + \globalletempty\nextTABLEgrayline + \global\TABLEgraydonetrue + \global\TABLEgraylinefalse}} + +\def\endTABLEgrayrow#1#2#3% + {\ifcase#1\relax + \global\chardef\TABLEendofrowheight\TABLErowfactor + \global\chardef\TABLEendofrowdepth \TABLErowfactor + \or + \global\chardef\TABLEendofrowheight\TABLErowfactor + \global\chardef\TABLEendofrowdepth \TABLErowfactor + \or + \global\chardef\TABLEendofrowheight\TABLErowfactor + \global\chardef\TABLEendofrowdepth \TABLErowzero + \or + \ifnum\TABLEforce=\TABLEforcelastrow + \global\chardef\TABLEendofrowheight\TABLErowzero + \global\chardef\TABLEendofrowdepth \TABLErowfactor + \else\ifnum\TABLEforce=\TABLEforcefirstrow + \global\chardef\TABLEendofrowheight\TABLErowfactor + \global\chardef\TABLEendofrowdepth \TABLErowzero + \else + \global\chardef\TABLEendofrowheight\TABLErowzero + \global\chardef\TABLEendofrowdepth \TABLErowzero + \fi\fi + \or + \global\chardef\TABLEendofrowheight\TABLErowzero + \global\chardef\TABLEendofrowdepth \TABLErowfactor + \fi} + +\def\defineTABLEshorthands% + {\def\SPAN##1{\use{##1}}% + \def\TWO {\use2}% + \def\THREE {\use3}% + \def\FOUR {\use4}% + \def\FIVE {\use5}% + \def\SIX {\use6}% + \def\REF {\ReFormat}} + +\def\defineTABLEunits + {\processaction + [\@@tidistance] + [ \v!none=>\OpenUp00\def\LOW{\Lower6 }, + \v!small=>\OpenUp00\def\LOW{\Lower6 }, % == baseline + \v!medium=>\OpenUp11\def\LOW{\Lower7 }, + \v!big=>\OpenUp22\def\LOW{\Lower8 }]% + \doifelse\@@tidistance\v!none + {\chardef\TABLErowfactor\zerocount} + {\chardef\TABLErowfactor\plustwo }} + +\def\dohandlebar % here ? + {\ifmmode + \@EA\domathmodebar + \else\ifintable + \@EAEAEA\domathmodebar + \else + \@EAEAEA\dotextmodebar + \fi\fi} + +% De macro's t.b.v. instellingen. + +\def\setuptables + {\dosingleargument\dosetuptables} + +\def\dosetuptables[#1]% + {\getparameters[\??ti][#1]% + \processaction + [\@@tialign] + [ \v!right=>\def\TABLEparalignment{\raggedright}, + \v!left=>\def\TABLEparalignment{\raggedleft}, + \v!middle=>\def\TABLEparalignment{\raggedcenter}, + \s!default=>\def\TABLEparalignment{\notragged}, + \s!unknown=>\def\TABLEparalignment{\notragged}]% + \assignalfadimension\@@tiVL\@@tiVLwidth 246% + \assignalfadimension\@@tiHL\@@tiHLheight246} + +\def\localTABLEsetup + {\@@ticommands\relax + \expanded{\switchtobodyfont[\@@tibodyfont]}% + \StrutHeightFactor 8 + \StrutDepthFactor 4 + \LineThicknessFactor4 + \NormalTLTU {.1pt}% + \NormalTSU {\normalbaselineskip\divide\StrutUnit 12 }% + \NormalTableUnits} + +%D And then I wrote the tabulate environment. That +%D alternative supports setting the rule thickness and color, +%D so here is the table alternative. + +\let\startglobalTABLEcolor\empty +\let\stopglobalTABLEcolor \empty + +\def\localTABLEsetup + {\@@ticommands\relax + % bodyfont + \expanded{\switchtobodyfont[\@@tibodyfont]}% + % linecolor + \doifsomething\@@tirulecolor + {\def\startglobalTABLEcolor{\localstartcolor[\@@tirulecolor]}% + \def\stopglobalTABLEcolor {\localstopcolor}}% + % linethickness + \LineThicknessFactor4 + \scratchdimen\@@tirulethickness + \divide\scratchdimen \LineThicknessFactor + \expanded{\NormalTLTU{\the\scratchdimen}}% + % spacing, was depth=4 height=8 (counters, sigh, now macros) + \doifelse\@@tiheight\v!strut + {\let\StrutHeightFactor\@@itheight} + {\let\StrutHeightFactor\@@tiheight}% + \doifelse\@@tidepth\v!strut + {\let\StrutDepthFactor\@@itdepth} + {\let\StrutDepthFactor\@@tidepth}% + \scratchdimen\StrutHeightFactor\points \multiply\scratchdimen 10% + \edef\StrutHeightFactor{\withoutpt\the\scratchdimen}% + \scratchdimen\StrutDepthFactor \points \multiply\scratchdimen 10% + \edef\StrutDepthFactor{\withoutpt\the\scratchdimen}% + % units + \NormalTSU{\normalbaselineskip\divide\StrutUnit 12 }% + \NormalTableUnits} + +\def\OpenUp#1#2% + {\scratchdimen\StrutHeightFactor \points \advance\scratchdimen #1\points + \edef\StrutHeightFactor{\withoutpt\the\scratchdimen}% + \scratchdimen\StrutDepthFactor \points \advance\scratchdimen #2\points + \edef\StrutDepthFactor{\withoutpt\the\scratchdimen}} + +%D As one can see, we didn't only add color, but also more +%D control over spacing. +%D +%D \startbuffer[a] +%D \starttable[|c|] +%D \HL +%D \VL \strut test \VL \FR +%D \VL \strut test \VL \MR +%D \VL \strut test \VL \MR +%D \VL \strut test \VL \LR +%D \HL +%D \stoptable +%D \stopbuffer +%D +%D \startbuffer[b] +%D \starttabulate[|c|] +%D \HL +%D \NC test \NC \NR +%D \NC test \NC \NR +%D \NC test \NC \NR +%D \NC test \NC \NR +%D \HL +%D \stoptabulate +%D \stopbuffer +%D +%D In the next example, the first table is defined as: +%D +%D \typebuffer[a] +%D +%D and the second one as: +%D +%D \typebuffer[b] +%D +%D The first table is typeset using the default height and +%D depth factors .8 and .4. The second table has both factors +%D set to \type {strut}, and the third table shows what +%D happens when we set the values to zero. The rightmost table +%D is typeset using the tabulate environment. +%D +%D \startcombination[4*1] +%D {$\vcenter{\getbuffer[a]}$} +%D {\hbox{h=.8 d=.4}} +%D {\setuptables[height=strut,depth=strut]$\vcenter{\getbuffer[a]}$} +%D {\hbox{h=d=\type{strut}}} +%D {\setuptables[height=0,depth=0]$\vcenter{\getbuffer[a]}$} +%D {\hbox{h=d=0}} +%D {$\vcenter{\getbuffer[b]}$} +%D {\hbox{tabulate}} +%D \stopcombination + +\setuptables + [HL=\v!medium, + VL=\v!medium, + NL=\v!small, + \c!frame=, + \c!align=\v!right, + \c!depth=.40, % \v!strut + \c!height=.80, % \v!strut + \c!rulethickness=\linewidth, + \c!rulecolor=, + \c!distance=\v!medium, + \c!bodyfont=\the\bodyfontsize, + \c!commands=, + \c!background=\v!screen, + \c!backgroundscreen=\@@rsscreen, + \c!backgroundcolor=, + \c!split=\v!auto] + +\def\ifintabel{\ifintable} % upward compatible + +\protect \endinput diff --git a/tex/context/base/tabl-tbl.tex b/tex/context/base/tabl-tbl.tex new file mode 100644 index 000000000..bc57a3abd --- /dev/null +++ b/tex/context/base/tabl-tbl.tex @@ -0,0 +1,1435 @@ +%D \module +%D [ file=core-tbl, +%D version=1998.11.03, +%D title=\CONTEXT\ Table Macros, +%D subtitle=Text Flow Tabulation, +%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 Table Macros / Tabulation} + +% \processbetween gebruiken in head/tail macros + +\unprotect + +% WATCH OUT: don't change this model else trialtypesetting +% compatibility problems + +% watch out, cells expand pretty late on a per row basis + +% |p2|p3| 2:3 +% spanning + +% Be careful with changing the hsize calculation in p mode; +% the following code works quite well: +% +% \setupfield [line][location=low,height=1.2\lineheight,width=\hsize] +% \definefield [test] [line] [line] [] +% +% \starttabulate[|l|p|] +% \NC test \NC \field [test] \NC \NR +% \stoptabulate + +% In-text tabbing environment +% +% \starttabulate[| separated template] % eg [|l|p|] or [|l|p|p|] +% \NC ... \NC ... \NC\NR +% \stoptabulate +% +% with: two pass auto width calculation when no p-width +% specified, even with multiple p's, see examples. + +% TaBlE compatible specifications: +% +% l align column/paragraph left +% r align column/paragraph right +% c align column/paragraph center +% p p(dimen) of automatisch als alleen p +% w column width +% f font#1 +% B bold +% I italic +% S slanted +% T type +% R roman +% m math +% M display math +% h hook (inner level or par lines) +% b before (may be command#1) +% a after +% i i skip left of column +% j i skip right of column +% k i skip around column + +% s setups + +% g g{char} align at char +% . align at . +% , align at , + +% Still to be done + +% N math numbers (best hook into existing digits mechanism) +% n numbers (best hook into existing digits mechanism) +% Q math numbers (best hook into existing digits mechanism) +% q numbers (best hook into existing digits mechanism) +% ~ \hskip.5em +% | check + +% nesting + +% 10 evt auto stack; dan wel andere signal dan void nodig + +% present but not yet 100% ok +% +% \FL top hrule +% \ML mid hrule (with auto split) +% \LL bottom hrule +% \HL + +% \VL as soon as needed +% color as soon as needed + +% \EQ \RQ \HQ equal (raw, hook) +% \NC \RC \HC normal (raw, hook) +% +% \NR + +% \HR : rule with lineheight + +% \autotabulaterule : with lineheight, not first/last +% \autotabulateline : spaced, not first/last +% \tabulaterule : with lineheight +% \tabulateline : spaced + +% tricky: align scans ahead, over # and expands ones before +% while doing + +% new: +% +% \starttabulate[|cg{.}|cg{,}|cg{,}|] +% \NC period \NC comma \NC comma \NC\NR +% \NG 100.000,00 \NG 100.000,00 \NG 100,00 \NC\NR +% \NG 10.000,00 \NG 10.000,00 \NG 1000,00 \NC\NR +% \NG 100,00 \NG 100,00 \NG 10,00 \NC\NR +% \NG 10 \NG 10 \NG 0,00 \NC\NR +% \stoptabulate +% +% \starttabulate[|c.|c,|c,|] +% \NC period \NC comma \NC comma \NC\NR +% \NG 100.000,00 \NG 100.000,00 \NG 100,00 \NC\NR +% \NG 10.000,00 \NG 10.000,00 \NG 1000,00 \NC\NR +% \NG 100,00 \NG 100,00 \NG 10,00 \NC\NR +% \NG 10 \NG 10 \NG 0,00 \NC\NR +% \stoptabulate + +% nice demo (for BG) +% +% \starttabulate[|r|b{$\star$}|ra{\percent}|b{=}|r|] +% \NC 500 \NC \NC 60 \NC \NC 300 \NC \NR +% \NC 500 \NC \NC 55 \NC \NC 275 \NC \NR +% \NC 500 \NC \NC 50 \NC \NC 250 \NC \NR +% \NC 500 \NC \NC 45 \NC \NC 225 \NC \NR +% \NC 500 \NC \NC 40 \NC \NC 200 \NC \NR +% \NC 500 \NC \NC 35 \NC \NC 175 \NC \NR +% \NC 500 \NC \NC 30 \NC \NC 150 \NC \NR +% \NC 500 \NC \NC 25 \NC \NC 125 \NC \NR +% \NC 500 \NC \NC 20 \NC \NC 100 \NC \NR +% \stoptabulate + +\newtoks \tabulatepreamble +\newtoks \tabulatebefore +\newtoks \tabulateafter +\newtoks \tabulatebmath +\newtoks \tabulateemath +\newtoks \tabulatefont +\newtoks \tabulatesettings +\newtoks \tabulatedummy + +\newcount \nofautotabulate +\newcount \tabulatecolumns +\newcount \tabulatecolumn + +\newcount \tabulateminplines +\newcount \tabulatemaxplines + +\newif \ifautotabulate +\newif \ifsplittabulate \splittabulatetrue + +\newif \ifhandletabulatepbreak \handletabulatepbreaktrue +\newif \iftabulatenopbreak \tabulatenopbreakfalse + +\newif \iftabulateequal +\newif \iftracetabulate +\newif \ifframedtabulate + +\newdimen \tabulatepwidth +\newdimen \tabulatewidth +\newdimen \tabulateunit +\newdimen \tabulatemaxpheight + +\newbox \tabulatebox + +% [|lg{.}|] => \NG 12.34 \NC + +\gdef\handletabulatecharalign#1 % space delimited ! + {\edef\alignmentclass{\the\tabulatecolumn}% + \edef\alignmentcharacter{\getvalue{\@@tabalign@@\the\tabulatecolumn}}% + \ifcase\tabulatepass\or + \setfirstpasscharacteralign\checkalignment{#1}% + \fi % force hsize + \setsecondpasscharacteralign\checkalignment{#1}} + +\def\noftabcolumns{16} + +\def\@@tabbox@@ {@@tabbox@} +\def\@@tabhook@@ {@@tabhook@} +\def\@@tabalign@@ {@@tabalign@} +\def\@@tabsetups@@{@@tabsetups@} + +% \dorecurse\noftabcolumns % quick and dirty stack +% {\@EA\newbox\csname\@@tabbox@@\recurselevel\endcsname} + +\def\tablebox#1% + {\csname\@@tabbox@@\number#1\endcsname} + +% \def\checktablebox#1% +% {\ifundefinedelse{\@@tabbox@@\number#1}% +% \expandafter\newbox\csname\@@tabbox@@\number#1\endcsname +% \fi} + +\def\initializetablebox#1% also used elsewhere + {\ifcsname\@@tabbox@@\number#1\endcsname + \global\setbox\csname\@@tabbox@@\number#1\endcsname\emptybox + \else + \expandafter\newbox\csname\@@tabbox@@\number#1\endcsname + \fi} + +% \def\initializetableboxes#1% hm, not that efficient, best make a simple dedicated tail recurser +% {\dorecurse#1{\initializetablebox\recurselevel}} + +\def\initializetableboxes#1% + {\scratchcounter#1\relax + \doinitializetableboxes} + +\def\doinitializetableboxes + {\ifnum\scratchcounter>\zerocount + \initializetablebox\scratchcounter + \advance\scratchcounter\minusone + \expandafter\doinitializetableboxes + \fi} + +\initializetableboxes\noftabcolumns + +\def\dotabulatenobreak + {\noalign + {\nobreak + \iftracetabulate + \red\hrule\!!height.5\linewidth\!!depth.5\linewidth + \par + \kern-\linewidth + \nobreak + \fi}} + +\let\notabulatehook\empty + +\def\checktabulatehook + {\ifnum\tabulatetype<\plustwo + \global\let\tabulatehook\notabulatehook + \else + \global\let\tabulatehook\dotabulatehook + \fi} + +\def\checktabulatesetups + {\getvalue{\@@tabsetups@@\the\tabulatecolumn}} + +\let\pretabrule \donothing +\let\posttabrule\donothing + +\def\dodosettabulatepreamble#1#2% + {\ifzeropt\tabulatewidth + \ifcase\tabulatemodus\relax + \let\preamblebox\empty + \else + \def\preamblebox{\autotabulatetrue}% + \fi + \else + \ifcase\tabulatemodus\relax + \edef\preamblebox{\hbox to \the\tabulatewidth}% + \else + \edef\preamblebox{\hsize\the\tabulatewidth}% + \fi + \fi + % + % less bytes + % + %\edef\preamblebox% + % {\ifcase\tabulatewidth + % \ifcase\tabulatemodus\relax\else\noexpand\autotabulatetrue\fi + % \els + % \ifcase\tabulatemodus\relax\hbox to\else\hsize\fi\the\tabulatewidth + % \fi}% + % + % 0 = NC column next EQ equal column + % 1 = RC column raw RQ equal column raw + % 2 = HC column hook HQ equal column hook + % some entries can be left out if we test for them being set + \@EA\appendtoks \@EA&\@EA\hskip\pretabskip\pretabrule##&\to\!!toksa + \appendtoks \ignorespaces\to\!!toksa + \@EA\appendtoks\@EA\global\@EA\tabulatecolumn\the\tabulatecolumns\relax\to\!!toksa + \appendtoks \checktabulatesetups\to\!!toksa + \appendtoks \checktabulatehook\to\!!toksa + \@EA\appendtoks \preamblebox\to\!!toksa + \appendtoks \bgroup\bbskip\bgroup#1\to\!!toksa + \appendtoks\ifnum\tabulatetype=\plusone \else \to\!!toksa + \@EA\appendtoks \the\tabulatebmath\to\!!toksa + \@EA\appendtoks \the\tabulatefont\to\!!toksa + \@EA\appendtoks \the\tabulatesettings\to\!!toksa + \@EA\appendtoks \the\tabulatebefore\to\!!toksa + \appendtoks\fi \to\!!toksa + \appendtoks \bgroup\ignorespaces\to\!!toksa + % + \appendtoks \tabulatehook##\to\!!toksa + % + %%\doifdefinedelse{\@@tabalign@@\tabulatecolumns} + %\doifdefinedelse{\@@tabalign@@\the\tabulatecolumns} + % {\appendtoks\handletabulatecharalign## \to\!!toksa} + % {\appendtoks\tabulatehook ##\to \!!toksa}% + % waarom kan ik hier geen \xx{##} geven, om een of + % andere reden passeert dan tex de hele regel (incl \NC's) + % als argument; elke delimiter <> space gaat trouwens fout + \appendtoks \unskip\unskip\ifmmode\else\endgraf\fi\egroup\to\!!toksa + \appendtoks\ifnum\tabulatetype=1 \else \to\!!toksa + \@EA\appendtoks \the\tabulateafter\to\!!toksa + \@EA\appendtoks \the\tabulateemath\to\!!toksa + \appendtoks\fi \to\!!toksa + \appendtoks #2\egroup\egroup\to\!!toksa + \@EA\appendtoks \@EA&\@EA\posttabrule\@EA\hskip\postabskip##\to\!!toksa + \appendtoks\NC\to\tabulatedummy + \let\bbskip\empty + \def\pretabskip{.5\tabulateunit}% + \let\postabskip\pretabskip + \let\gettabulateexit\dogettabulateexit + \tabulatewidth\zeropoint} + +% todo: we can speed up this module a bit +% +% \expanded{\!!toksa{\the\!!toksa +% &\hskip\pretabskip\noexpand\pretabrule####& +% \ignorespaces +% \global\tabulatecolumn\the\tabulatecolumns +% \noexpand\checktabulatesetups +% \noexpand\checktabulatehook +% \preamblebox +% \bgroup\noexpand\bbskip\bgroup\normalunexpanded{#1}% +% \noexpand\ifnum\tabulatetype=\plusone \noexpand\else +% \the\tabulatebmath +% \the\tabulatefont +% \the\tabulatesettings +% \the\tabulatebefore +% \noexpand\fi +% \bgroup\ignorespaces +% \noexpand\tabulatehook####% +% \unskip\unskip\noexpand\ifmmode\noexpand\else\endgraf\noexpand\fi\egroup +% \noexpand\ifnum\noexpand\tabulatetype=1 \noexpand\else +% \the\tabulateafter +% \the\tabulateemath +% \noexpand\fi +% \normalunexpanded{#2}\egroup\egroup +% &\noexpand\posttabrule\hskip\noexpand\postabskip####}}% + +\def\dosettabulatepreamble + {\ifx\next\relax + \let\nextnext\relax % == \expandafter\gobbleoneargument + \else + \let\nextnext\settabulatepreamble + \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 + \else\ifx f\next \let\nextnext\gettabulatefont + \else\ifx B\next \tabulatefont{\bf}% + \else\ifx I\next \tabulatefont{\it}% + \else\ifx S\next \tabulatefont{\sl}% + \else\ifx T\next \tabulatefont{\tt}% + \else\ifx R\next \tabulatefont{\rm}% + \else\ifx m\next \tabulatebmath{$}\tabulateemath{$}% + \else\ifx M\next \tabulatebmath{$\displaystyle}\tabulateemath{$}% + \else\ifx h\next \let\nextnext\gettabulatehook + \else\ifx b\next \let\nextnext\gettabulatebefore + \else\ifx a\next \let\nextnext\gettabulateafter + \else\ifx i\next \let\nextnext\gettabulatepreskip + \else\ifx j\next \let\nextnext\gettabulateposskip + \else\ifx k\next \let\nextnext\gettabulatepreposskip + \else\ifx X\next \let\nextnext\gettabulateexit % internal + \else\ifx e\next \appendtoks\global\tabulateequaltrue\to\tabulatesettings + \else\ifx ~\next \appendtoks\fixedspaces\to\tabulatesettings + \else\ifx g\next \let\nextnext\gettabulatealign + \else\ifx .\next \def\nextnext{\gettabulatealign.}% + \else\ifx ,\next \def\nextnext{\gettabulatealign,}% + \else \message{unknown preamble key [\meaning\next]}% + \fi\fi\fi\fi\fi \fi\fi\fi\fi\fi \fi\fi\fi\fi\fi + \fi\fi\fi\fi\fi \fi\fi\fi\fi\fi \fi\fi + \fi + \nextnext} + +\def\dogettabulateexit + {\let\postabskip\!!zeropoint + \settabulatepreamble} + +\let\gettabulateexit\dogettabulateexit + +\def\gettabulatepreskip#1% + {\doifnumberelse{#1} + {\scratchdimen#1\tabulateunit\let\next\empty} + {\scratchdimen.5\tabulateunit\def\next{#1}}% + \edef\pretabskip{\the\scratchdimen}% + \@EA\settabulatepreamble\next} + +\def\gettabulateposskip#1% + {\doifnumberelse{#1} + {\scratchdimen#1\tabulateunit\let\next\empty} + {\scratchdimen.5\tabulateunit\def\next{#1}}% + \edef\postabskip{\the\scratchdimen}% + \let\gettabulateexit\settabulatepreamble + \@EA\settabulatepreamble\next} + +\def\gettabulatepreposskip#1% + {\doifnumberelse{#1} + {\scratchdimen#1\tabulateunit\let\next\empty} + {\scratchdimen.5\tabulateunit\def\next{#1}}% + \edef\pretabskip{\the\scratchdimen}% + \let\postabskip\pretabskip + \let\gettabulateexit\settabulatepreamble + \@EA\settabulatepreamble\next} + +\def\gettabulatesetups#1% + {\setvalue{\@@tabsetups@@\the\tabulatecolumns}{\setups[#1]}% + \settabulatepreamble} + +\def\gettabulatehook#1% + {\setvalue{\@@tabhook@@\the\tabulatecolumns}{#1}% + \settabulatepreamble} + +\def\gettabulatealign#1% + {\setvalue{\@@tabalign@@\the\tabulatecolumns}{#1}% + \settabulatepreamble} + +\def\gettabulatebefore#1% + {\tabulatebefore{#1}% + \settabulatepreamble} + +\def\gettabulateafter#1% + {\tabulateafter{#1}% + \settabulatepreamble} + +\def\gettabulatefont#1% + {\tabulatefont{#1}% + \settabulatepreamble} + +\def\gettabulatewidth + {\let\tabulatemodus\zerocount + \let\tabulatedimen\zerocount + \doifnextcharelse(\dogettabulatewidth\settabulatepreamble} + +\def\gettabulateparagraph + {\doifnextcharelse{(} + {\let\tabulatemodus\plusone + \let\tabulatedimen\plusone + \dogettabulatewidth} + {\let\tabulatemodus\plustwo + \let\tabulatedimen\zerocount + \settabulatepreamble}} + +% \def\dogettabulatewidth(#1)% +% {\tabulatewidth#1\relax +% \ifnum\tabulatedimen=\plusone +% \global\advance\tabulatepwidth\tabulatewidth +% \fi +% \settabulatepreamble} + +% \def\dogettabulatewidth(#1)% +% {\doifelse{#1}\v!passend +% {\let\tabulatemodus\plusthree} +% {\tabulatewidth#1\relax}% +% \ifnum\tabulatedimen=\plusone +% \global\advance\tabulatepwidth\tabulatewidth +% \fi +% \settabulatepreamble} + +% \startbuffer +% \toplinebox{\framed[width=3cm,height=2cm]{tufte}} +% \stopbuffer +% \starttabulate[|p(fixed)|p|] +% \dorecurse{100}{\NC \getbuffer \NC test \par test \par \NC \NR} +% \stoptabulate +% \starttabulate[|p(fit)|p|] +% \dorecurse{100}{\NC \getbuffer \NC test \par test \par \NC \NR} +% \stoptabulate + +\def\dogettabulatewidth(#1)% + {\processallactionsinset + [#1]% + [ \v!fit=>\let\tabulatemodus\plusthree, + \v!fixed=>\let\tabulatemodus\plusthree + \tabulatenopbreaktrue, + \s!unknown=>\tabulatewidth#1\relax]% + \ifnum\tabulatedimen=\plusone + \global\advance\tabulatepwidth\tabulatewidth + \fi + \settabulatepreamble} + +\def\settabulatepreamble + {\afterassignment\dosettabulatepreamble\let\next=} + +\def\tabulateraggedright {\ifnum\tabulatetype=\plusone \else\raggedright \fi} +\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} % never change this to a fill + +\bgroup \catcode`\|=\@@other + +\gdef\nexttabulate#1|% + {\let\tabulatealign\@@tabulatealign + \let\tabulatemodus\zerocount + \let\tabulatedimen\zerocount + \tabulatebefore \emptytoks + \tabulateafter \emptytoks + \tabulatebmath \emptytoks + \tabulateemath \emptytoks + \tabulatefont \emptytoks + \tabulatesettings\emptytoks + \global\advance\tabulatecolumns\plusone + \letvalue{\@@tabsetups@@\the\tabulatecolumns}\donothing + \settabulatepreamble#1\relax\relax % permits i without n + \ifcase\tabulatemodus\relax + \ifcase\tabulatealign\relax + \dodosettabulatepreamble\empty \tabulatehss \or + \dodosettabulatepreamble\empty \tabulatehss \or + \dodosettabulatepreamble\tabulatehss\empty \or + \dodosettabulatepreamble\tabulatehss\tabulatehss \fi + \or % fixed width + \ifcase\tabulatealign\relax + \dodosettabulatepreamble \bskip \eskip \or + \dodosettabulatepreamble{\bskip\tabulateraggedright }\eskip \or + \dodosettabulatepreamble{\bskip\tabulateraggedleft }\eskip \or + \dodosettabulatepreamble{\bskip\tabulateraggedcenter}\eskip \fi + \or % auto width + \global\advance\nofautotabulate\plusone + \ifcase\tabulatealign\relax + \dodosettabulatepreamble \bskip \eskip \or + \dodosettabulatepreamble{\bskip\tabulateraggedright }\eskip \or + \dodosettabulatepreamble{\bskip\tabulateraggedleft }\eskip \or + \dodosettabulatepreamble{\bskip\tabulateraggedcenter}\eskip \fi + \or % simple + \dodosettabulatepreamble \xbskip \xeskip + \fi + \futurelet\next\donexttabulate} + +\egroup + +\def\donexttabulate + {\ifx\next\relax\else + \expandafter\nexttabulate + \fi} + +\def\splitofftabulatebox + {\dontcomplain + \global\setbox\tabulatebox % % % global ? % % % + \vsplit\tablebox\tabulatecolumn to \lineheight + \setbox\tabulatebox\normalvbox + {\unvbox\tabulatebox}% + \setbox\tabulatebox\hbox to \wd\tabulatebox + {\hss\dotabulatehook{\box\tabulatebox}\hss}% + \ht\tabulatebox\strutht + \dp\tabulatebox\strutdp + \box\tabulatebox} + +\def\dotabulatehook {\getvalue{\@@tabhook@@ \the\tabulatecolumn}} +\def\dotabulatealign {\getvalue{\@@tabalign@@ \the\tabulatecolumn}} + +\def\resettabulatepheight + {\global\tabulateminplines\plusone + \getnoflines\tabulatemaxpheight + \global\tabulatemaxplines\noflines + \global\tabulatemaxpheight\zeropoint} + +\def\settabulatepheight + {\scratchdimen\ht\tablebox\tabulatecolumn\relax + \ifdim\scratchdimen>\tabulatemaxpheight + \global\tabulatemaxpheight\scratchdimen + \fi} + +\def\handletabulatepbreak + {\TABLEnoalign + {\ifhandletabulatepbreak + \iftabulatenopbreak + \dotabulatenobreak + \else\ifnum\tabulatemaxplines>\plusone + \ifnum\tabulateminplines=\plusone + \dotabulatenobreak + \fi + \global\advance\tabulateminplines\plusone + \ifnum\tabulateminplines=\tabulatemaxplines\relax + \dotabulatenobreak + \fi + \fi \fi + \fi}} + +%D \startbuffer +%D \starttabulate[|c|p|p|] +%D \NC \bf Alpha \NC \bf Beta \NC \bf Gamma \NC\NR +%D \NC 1 \NC right indeed \NC definitely wrong \NC\NR +%D \NC 2 \NC \thinrules[n=3] \NC \thinrules[n=3] \NC\NR +%D \NC 3 \NC oh yes \NC simply no \NC\NR +%D \NC 4 \NC very true \NC as false as can be \NC\NR +%D \NC 5 \NC \thinrules[n=5] \NC \thinrules[n=5] \NC\NR +%D \NC 6 \NC \thinrules[n=3] \NC \thinrules[n=4] \NC\NR +%D \stoptabulate +%D \stopbuffer +%D +%D \typebuffer {\tracetabulatetrue\getbuffer} +%D +%D \startbuffer +%D \starttabulate[|c|p|p|] +%D \NC \bf Alpha \NC \bf Beta \NC \bf Gamma \NC\NR +%D \NC 1 \NC right indeed \NC definitely wrong \NC\NR +%D \NC 2 \NC oh yes \NC simply no \NC\NR +%D \NC 3 \NC very true \NC as false as can be \NC\NR +%D \NC 4 \NC the whole truth \NC but the truth \NC\NR +%D \stoptabulate +%D \stopbuffer +%D +%D \typebuffer {\tracetabulatetrue\getbuffer} + +% \definetabulate +% \redefinetabulate +% \starttabulate[preamble] +% \starttabulate -> \starttabulate[|l|p|] + +\bgroup \catcode`\|=\@@other + +\gdef\definetabulate + {\dotripleempty\dodefinetabulate} + +\gdef\dodefinetabulate[#1][#2][#3]% + {\ifthirdargument + \doifundefined{\??tt#1::\c!unit} + {\copyparameters + [\??tt#1::][\??tt\v!tabulate::]% + [\c!frame,\c!distance,\c!unit,\c!before,\c!bodyfont,\c!after, + \c!inner,\c!indenting,\c!margin,\c!align,\c!header,\c!title, + \c!rulecolor,\c!rulethickness,\c!split,EQ]}% + \copyparameters + [\??tt#1::#2][\??tt#1::]% + [\c!unit,\c!distance,\c!before,\c!bodyfont,\c!after, + \c!inner,\c!indenting,\c!frame,\c!split,\c!header,\c!title, + \c!margin,\c!align,\c!rulecolor,\c!rulethickness,EQ]% + \setvalue{\e!start#1::#2}{\dofinalstarttabulate[#1][#2][#3]}% + \setvalue{\e!start#1}{\bgroup\dosubstarttabulate[#1]}% + \letvalue{\??tt#1-\v!header}\empty + \letvalue{\??tt#1-\v!footer }\empty + \else\ifsecondargument + \definetabulate[#1][][#2]% + \else + \definetabulate[#1][][|l|p|]% + \fi\fi} + +\egroup + +\let\tabulateheadcontent\empty +\let\tabulatetailcontent\empty + +\newconditional\tabulatesomeamble + +\def\checkfulltabulatecontent % - needed, else confusion with \c!header + {\ifundefined{\??tt\currenttabulate-\v!header}% + \let\tabulateheadcontent\empty + \else + \def\tabulateheadcontent + {\TABLEnoalign{\global\settrue\tabulatesomeamble}% + \csname\??tt\currenttabulate-\v!header\endcsname + \TABLEnoalign{\global\setfalse\tabulatesomeamble}}% + \fi + \ifundefined{\??tt\currenttabulate-\v!footer}% + \let\tabulatetailcontent\empty + \else + \def\tabulatetailcontent + {\TABLEnoalign{\global\settrue\tabulatesomeamble}% + \csname\??tt\currenttabulate-\v!footer\endcsname + \TABLEnoalign{\global\setfalse\tabulatesomeamble}}% + \fi} + +% \def\fulltabulatecontent +% {\tabulateheadcontent +% \tabulatecontent +% \tabulatetailcontent} + +\def\fulltabulatecontent + {\tabulateheadcontent + \tabulatecontent + \tabulatetailcontent + \removefunnytabulateline} + +\def\removefunnytabulateline + {\ifhmode + \strut\crcr + \TABLEnoalign{\kern-\lineheight}% + \fi} + +\setvalue{\e!start\v!tabulatehead}% + {\dosingleempty\dostartstarttabulatehead} + +\def\dostartstarttabulatehead[#1]% + {\processcontent{\e!stop\v!tabulatehead}\next + {\letvalue{\??tt\iffirstargument#1\else\v!tabulate\fi::-\v!header}\next}} + +\setvalue{\e!start\v!tabulatetail}% + {\dosingleempty\dostartstarttabulatetail} + +\def\dostartstarttabulatetail[#1]% + {\processcontent{\e!stop\v!tabulatetail}\next + {\letvalue{\??tt\iffirstargument#1\else\v!tabulate\fi::-\v!footer}\next}} + +\def\dosubstarttabulate + {\dodoubleempty\dodosubstarttabulate} + +\def\dodosubstarttabulate[#1][#2]% + {\getvalue{\e!start#1::\ifundefined{\e!start#1::#2}\else#2\fi}} + +\setvalue{\e!start\v!tabulate}% + {\bgroup\dodoubleempty\donormalstarttabulate} + +\bgroup + +\gdef\donormalstarttabulate[#1][#2]% + {\ifsecondargument + \getparameters[\??tt\v!tabulate::][#2]% + \fi + \iffirstargument + \def\next{\dofinalstarttabulate[\v!tabulate][][#1]}% + \else + \def\next{\dofinalstarttabulate[\v!tabulate][][|l|p|]}% + \fi + \next} + +\egroup + +% The much neede hook: + +\newtoks\everytabulate + +% An example of its usage: + +\appendtoks \optimizeverbatimfalse \to \everytabulate +\appendtoks \let\recodeverbatimmode\plustwo \to \everytabulate + +% A status variable: + +\chardef\tabulatepass=0 + +\def\tabulateparameter#1{\csname\??tt\currenttabulate#1\endcsname} + +\bgroup + \catcode`\|=\@@other \gdef\@@otherbar{|} + \catcode`\|=\@@active \gdef\@@useotherbar{\let|\@@otherbar} +\egroup + +\def\dofinalstarttabulate[#1][#2][#3]% identifier sub preamble + {\edef\currenttabulate{#1::#2}% + \ifinsidefloat \else + \whitespace + \tabulateparameter\c!before + \fi + \bgroup + \resetcharacteralign + % todo: spacing around tabulate when bodyfont is set + % expansion en test needed ? + \splittabulatetrue + \processaction + [\tabulateparameter\c!split] + [% \v!yes=>\splittabulatetrue, + % \v!repeat=>\splittabulatetrue, % todo, default yes + \v!no=>\splittabulatefalse, + \v!auto=>\ifinsidefloat\ifinsidesplitfloat\else\splittabulatefalse\fi\fi]% + \doifvaluesomething{\??tt\currenttabulate\c!bodyfont} + {\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 + \tabulateparameter\c!inner + \scratchdimen\leftskip + \advance\scratchdimen \hangindent + \doifvalue{\??tt\currenttabulate\c!indenting}\v!yes + {\advance\scratchdimen \parindent}% \ctxparindent + \edef\tabulateindent{\the\scratchdimen}% + \!!toksb\emptytoks + \def\dorepeat*##1##2% + {\dorecurse{##1}{\appendtoks##2\to\!!toksb}\do}% + \def\do + {\futurelet\next\dodo}% + \def\dodo % \@EAEAEA gebruiken + {\ifx\next\relax + % exit + \else\ifx*\next + \let\next\dorepeat + \else\ifx\bgroup\next + \let\next\dododo + \else + \let\next\dodododo + \fi\fi\fi + \next}% + \def\dododo##1% + {\appendtoks{##1}\to\!!toksb\do}% + \def\dodododo##1% + {\appendtoks##1\to\!!toksb\do}% + \global\tabulatecolumn\zerocount +% \do#3\relax +\bgroup\@@useotherbar\expanded{\egroup\noexpand\do#3\relax}% + \processcontent + {\e!stop#1}% \currenttabulate} + \tabulatecontent + {\@EA\processtabulate\@EA[\the\!!toksb]}} + +\chardef\tabulatetype=0 + +% 0 = NC column next EQ equal column +% 1 = RC column raw RQ equal column raw +% 2 = HC column hook HQ equal column hook + +\newif\iftabulatefirstflushed + +\def\tabulateEQ + {\iftabulatefirstflushed\else\tabulateparameter{EQ}\fi + \global\tabulateequalfalse} + +% \def\tabulatenormalcolumn#1% +% {&\iftabulateequal\tabulateEQ\fi&\global\chardef\tabulatetype#1&} +% +% \def\tabulateequalcolumn#1% +% {&\tabulateEQ&\global\chardef\tabulatetype#1&} +% +% however, \unskip en \ignorespaces permit usage in complex XML/\starttabulate + +\def\tabulatenormalcolumn#1% + {\unskip&\iftabulateequal\tabulateEQ\fi&\global\chardef\tabulatetype#1&% + \ignorespaces} + +\def\tabulateequalcolumn#1% + {\unskip&\tabulateEQ&\global\chardef\tabulatetype#1&% + \ignorespaces} + +\def\tabulateautocolumn + {\tabulatenormalcolumn\zerocount + \ifnum\tabulatecolumn>\tabulatecolumns\relax + \expandafter\NR + \else + \expandafter\ignorespaces % interferes with the more tricky hooks + \fi} + +\def\setquicktabulate#1% see \startlegend \startgiven + {\let#1\tabulateautocolumn + \let\\\tabulateautocolumn} + +%\def\dotabulateruleseperator +% {\vskip\strutdp} + +\def\dotabulateruleseperator % can be sped up + {\bgroup + \let\factor\!!plusone + \scratchskip\strutdp + \ExpandFirstAfter\processallactionsinset + [\tabulateparameter\c!distance] + [ \v!blank=>\scratchskip\bigskipamount, + \v!depth=>\scratchskip\strutdp, + \v!small=>\def\factor{.25}, + \v!medium=>\def\factor{.5}, + \v!big=>, + \v!none=>\scratchskip\zeropoint\def\factor{0}, + \v!grid=>\scratchskip\zeropoint\def\factor{0}, + \s!unknown=>\scratchskip\commalistelement]% + \scratchdimen\factor\scratchskip + \ifconditional\tabulatesomeamble\kern\else\vskip\fi\scratchdimen % new + \egroup} + +\def\dodotabulaterule#1% + {\color + [\tabulateparameter\c!rulecolor] + {\scratchdimen\tabulateparameter\c!rulethickness#1}} + +\def\dotabulaterule + {\dodotabulaterule + {\hrule\!!height.5\scratchdimen\!!depth.5\scratchdimen\relax + \doifvalue{\??tt\currenttabulate\c!distance}\v!grid + {\kern-\scratchdimen}}} % experimental tm-prikkels + +\def\dotabulatelinerule + {\multispan\totaltabulatecolumns % \multispan is a plain macro + % for the moment this one + \strut\hskip\tabulateparameter\c!margin + % neg values are ok ! + \hskip\tabulateindent % new august 2003 + \dodotabulaterule + {\!!heighta.5\lineheight + \advance\!!heighta-\strutdepth + \!!deptha-\!!heighta + \advance\!!deptha\scratchdimen + \leaders\hrule\!!height\!!heighta\!!depth\!!deptha\hfill}% + \cr} + +%D When set to true, no (less) break optimization is done. + +\newif\iftolerantTABLEbreak + +%D The main processing macro is large but splitting it up +%D would make things less clear. + +\def\doregistertabulateparoptions + {\iftrialtypesetting \else + \registerparoptions + \ifinsidefloat + % that is, an unbreakable one + \global\let\registertabulateparoptions\empty + \else + % unsafe in crossing pages, at each b... + % \global\let\registertabulateparoptions\empty + \fi + \fi} + +\appendtoks + \global\let\registertabulateparoptions\doregistertabulateparoptions +\to \everytabulate + +\newtoks\everytabulaterow + +\appendtoks + \registertabulateparoptions +\to \everytabulaterow + +\def\flushtabulateindent + {\ifnum\tabulatecolumn=\zerocount + \hbox to \tabulateindent + {% we now have a local hsize, and since we want to + % register positional info (i.e. real hsizes) we + % need to reconstitute the original hsize + \advance\hsize\tabulateindent + % this is indeed rather messy and took a few hours + % to dis/uncover + \the\everytabulaterow + \hss}% + \fi} + +\def\totaltabulatecolumns{0} + +\def\handletabulatedigits{\digits} + +%D Beware, we cannot use \type {\unexpanded} on \type {\HL} +%D cum suis, since \TEX's hard coded noalign lookahead fails +%D on it! I mistakenly added this for a while. + +\chardef\tabulaterepeathead\zerocount + +\newcount\noftabulatelines +\newcount\totalnoftabulatelines +\newcount\minusnoftabulatelines + +\setvalue{\??tt:\c!align:\v!normal}{0} +\setvalue{\??tt:\c!align:\v!right }{1} +\setvalue{\??tt:\c!align:\v!left }{2} +\setvalue{\??tt:\c!align:\v!middle}{3} + +\setvalue{\??tt:\c!header:\v!repeat}{\plusone} +\setvalue{\??tt:\c!header:\v!text }{\plustwo} + +\bgroup \catcode`\|=\@@other + +\gdef\processtabulate[|#1|]% in the process of optimizing + {\tabulateunit\tabulateparameter\c!unit + \checkfulltabulatecontent + \globallet\tabulateruledepth \!!zeropoint + \globallet\tabulateruleheight\!!zeropoint + \edef\@@tabulatealign{\executeifdefined{\??tt:\c!align:\tabulateparameter\c!align}0}% +% \ExpandFirstAfter\processaction % use \setalignmentswitch instead +% [\tabulateparameter\c!align] +% [ \v!normal=>\def\@@tabulatealign{0},% = default value +% \v!right=>\def\@@tabulatealign{1},% chardefs gebruiken +% \v!left=>\def\@@tabulatealign{2},% +% \v!middle=>\def\@@tabulatealign{3},% +% \s!default=>\def\@@tabulatealign{0},% +% \s!unknown=>\def\@@tabulatealign{0}]% + \let\pretabskip\!!zeropoint + \def\postabskip{.5\tabulateunit}% + \global\tabulatecolumns\zerocount + \global\nofautotabulate\zerocount + \global\noftabulatelines\zerocount + \totalnoftabulatelines\noftabulatelines + \minusnoftabulatelines\noftabulatelines + \global\tabulatepwidth\zeropoint + \global\tabulateequalfalse + \resettabulatepheight + \ifinsidesplitfloat + \donetrue + \else\ifinsidefloat + \donefalse + \else + \donetrue + \fi\fi + \ifdone + \chardef\tabulaterepeathead\executeifdefined{\??tt:\c!header:\tabulateparameter\c!header}\zerocount +% \processaction +% [\tabulateparameter\c!header] +% [\v!repeat=>\let\tabulaterepeathead\plusone, +% \v!text=>\let\tabulaterepeathead\plustwo]% + \fi + \unexpanded \def\NC{\tabulatenormalcolumn0}% + \unexpanded \def\RC{\tabulatenormalcolumn1}% + \unexpanded \def\HC{\tabulatenormalcolumn2}% + \unexpanded \def\EQ{\tabulateequalcolumn 0}% + \unexpanded \def\RQ{\tabulateequalcolumn 1}% + \unexpanded \def\HQ{\tabulateequalcolumn 2}% + \unexpanded \def\NG{\NC\handletabulatecharalign}% + \unexpanded \def\NN{\NC\handletabulatedigits}% new, undocumented, test first + \unexpanded \def\ND{\NC\handletabulatedigits}% same, for old times sake + \def\tabulaterule{\HR}% a rule with lineheight + \def\tabulateline{\HL}% just a spaced rule + \def\tabulateautorule{\doHR\plusone}% + \def\tabulateautoline{\doHL\plusone}% + \def\HR{\doHR\zerocount} + \def\HL{\doHL\zerocount} + \unexpanded \def\NR % next row + {\global\advance\noftabulatelines\plusone + \global\tabulatefirstflushedfalse + \global\tabulateequalfalse + \global\tabulatecolumn\zerocount + \resettabulatepheight + \unskip\unskip\crcr\flushtabulated + \TABLEnoalign + {\iftolerantTABLEbreak\else + \ifconditional\tabulatesomeamble \ifcase\tabulaterepeathead \else + \allowbreak + \fi \fi + \ifnum\noftabulatelines=\plusone + \dotabulatenobreak + \else\ifnum\noftabulatelines=\minusnoftabulatelines + \ifnum\tabulatemaxplines<\plustwo + \dotabulatenobreak + \else + \allowbreak % needed with pbreak prevention + \fi + \else + \allowbreak % needed with pbreak prevention + \fi\fi + \fi + \global\tabulatefirstflushedfalse}}% + \let\HL\empty % not needed + \let\SR\NR \let\AR\NR + \let\FL\empty \let\FR\NR + \let\ML\empty \let\MR\NR + \let\LL\empty \let\LR\NR + \let\doHR\gobbleoneargument + \let\doHL\gobbleoneargument + \global\let\flushtabulated\empty +% \let\savedbar|\let|\nexttabulate + \tabskip\zeropoint + \ifdim\tabulateparameter\c!margin>\zeropoint + \!!toksa{&\flushtabulateindent\strut##% + \tabskip\tabulateparameter\c!margin\strut + &##\tabskip\zeropoint}% + \else + \!!toksa{&\flushtabulateindent\strut##% + &##\tabskip\zeropoint}% + \fi + \tabulatewidth\zeropoint + % |#1X|\relax + \nexttabulate #1X|\relax + \scratchcounter\tabulatecolumns + \multiply\scratchcounter3% + \advance\scratchcounter4% + \edef\totaltabulatecolumns{\the\scratchcounter}% + \tabulatewidth\zeropoint + % \dorecurse\tabulatecolumns % can be made faster + % {\doifundefinedelse{\@@tabbox@@\recurselevel} + % {\expandafter\newbox\csname\@@tabbox@@\recurselevel\endcsname}% + % {\global\setbox\csname\@@tabbox@@\recurselevel\endcsname\emptybox}}% + \initializetableboxes\tabulatecolumns + \appendtoks&##\to\!!toksa + \appendtoks\global\advance\tabulatecolumn\plusone\to\!!toksa + \appendtoks\NC\unskip\unskip\crcr\flushtabulated\to\tabulatedummy % no count + \global\tabulatecolumn\zerocount + \resettabulatepheight + \def\bskip + {\setbox\tabulatebox\vbox\bgroup + \global\let\tabulatehook\notabulatehook}% + \def\eskip + {\par\egroup + \global\let\tabulatehook\dotabulatehook}% + \def\xbskip + {\hbox\bgroup\vbox\bgroup + \global\let\tabulatehook\notabulatehook}% + \def\xeskip + {\par\egroup\egroup + \global\let\tabulatehook\dotabulatehook}% + % \let|\savedbar + \global\let\tabulatehook\dotabulatehook + \doifvalue{\??tt\currenttabulate\c!indenting}\v!no\forgetparindent + \ifinsidefloat + \let\tabulateindent\!!zeropoint + \else + \setlocalhsize \hsize\localhsize + \fi + \dontcomplain + \forgetall % hm, interference with \forgetparindent ^^^ probably bug, to be solved + \setbox0\vbox % outside \if because of line counting + {\notesenabledfalse + \let\tabulateindent\!!zeropoint + \trialtypesettingtrue % very important + \@EA\halign\@EA{\the\!!toksa\crcr\fulltabulatecontent\crcr}}% + \ifnum\nofautotabulate>\zerocount + % so, even if the natural size is larger, in the final + % run, we force the calculated width + \tabulatewidth\hsize + \advance\tabulatewidth -\wd0 + \advance\tabulatewidth -\tabulatepwidth + \ifnum\nofautotabulate>\zerocount + \divide\tabulatewidth \nofautotabulate\relax + \fi + \fi + \def\xbskip{\bskip}% + \def\xeskip{\eskip}% + \ifsplittabulate + \splittopskip\strutht + \global\let\flushtabulatedindeed\empty + \long\def\bbskip + {\ifvoid\tablebox\tabulatecolumn + \ifx\flushtabulatedindeed\empty\else + \setbox0\hbox + \fi + \fi}% + \def\bskip + {\ifvoid\tablebox\tabulatecolumn + \global\setbox\tablebox\tabulatecolumn\vbox + \bgroup + \global\let\tabulatehook\notabulatehook + \ifautotabulate\hsize\tabulatewidth\fi + % \begstrut % interferes with pre-\pars + % evt: \appendtoks\begstrut\to\everypar + \ignorespaces + \def\eskip + {\par\egroup + \settabulatepheight + \global\let\tabulatehook\dotabulatehook + \splitofftabulatebox}% + \else + \let\eskip\empty + \dontcomplain + \global\let\tabulatehook\dotabulatehook + \expandafter\splitofftabulatebox + \fi}% + \gdef\flushtabulated + {\TABLEnoalign % noalign % no interference ! + {\global\let\flushtabulatedindeed\empty + \global\tabulatecolumn\zerocount + \handletabulatepbreak + \dorecurse\tabulatecolumns % was: \noftabcolumns + {\ifvoid\tablebox\recurselevel\else + \gdef\flushtabulatedindeed{\the\tabulatedummy}% + \fi}% + \global\tabulatefirstflushedtrue}% + \flushtabulatedindeed}% + \else + % tabhook op alles ? + \def\bskip + {\vtop\bgroup + \ifautotabulate\hsize\tabulatewidth\fi + % \begstrut % interferes with pre-\pars + % evt: \appendtoks\begstrut\to\everypar + \ignorespaces}% + \def\eskip % vertical strut added august 2003 + {\par\verticalstrut\vskip-\struttotal\egroup}% + \fi + \totalnoftabulatelines\noftabulatelines + \minusnoftabulatelines\numexpr\noftabulatelines+\minusone\relax + \global\noftabulatelines\zerocount + \def\doHL##1% ##1 ignored + {\TABLEnoalign + {\csname + \ifnum\noftabulatelines=\zerocount F\else + \ifnum\noftabulatelines=\totalnoftabulatelines L\else + M\fi\fi + L\endcsname}}% + \def\doHR##1% horizontal rule line (break untested) + {\TABLEnoalign + {\globallet\TABLEautoline\dotabulatelinerule + \ifcase##1\or + \ifnum\noftabulatelines=\zerocount + \gdef\TABLEautoline{\TABLEnoalign{}}% + \else\ifnum\noftabulatelines=\totalnoftabulatelines + \gdef\TABLEautoline{\TABLEnoalign{}}% + \fi\fi + \fi + \dotabulatenobreak}% + \TABLEautoline + \TABLEnoalign + {\nobreak + \ifx\TABLEautoline\dotabulatelinerule\kern-\lineheight\fi + \ifnum\noftabulatelines=\totalnoftabulatelines + \@EA\dotabulatenobreak + \else + \@EA\allowbreak + \fi}% + \TABLEautoline + \TABLEnoalign + {\dotabulatenobreak}}% + \doifelsevalue{\??tt\currenttabulate\c!rule}\v!line + {\let\HL \HR + \let\tabulateautoline\tabulateautorule + \let\tabulateline \tabulaterule}% + {\def\HL{\doHL\zerocount}}% + \def\tablebaselinecorrection + {\def\dobaselinecorrection + {\vskip-\prevdepth + \vskip\strutdp + \vskip\strutdp}% + \baselinecorrection}% + \def\FL{\TABLEnoalign + {\ifinsidefloat\else + \doifemptyvalue{\??tt\currenttabulate\c!before} % no expansion + {\tablebaselinecorrection}% + \fi + \dotabulaterule + \dotabulatenobreak + \dotabulateruleseperator + \prevdepth\strutdp + \dotabulatenobreak}}% + \def\ML{\TABLEnoalign + {\dotabulateruleseperator + \dotabulaterule + \ifnum\noftabulatelines>\plusone + \ifnum\noftabulatelines<\minusnoftabulatelines + \vskip\topskip\allowbreak\vskip-\topskip + \vskip-\tabulateparameter\c!rulethickness + \dotabulaterule + \fi + \fi + \dotabulateruleseperator}}% + \def\LL{\TABLEnoalign + {\dotabulatenobreak + \dotabulateruleseperator + \dotabulatenobreak + \dotabulaterule + \ifinsidefloat\else + \doifemptyvalue{\??tt\currenttabulate\c!after} % no expansion + {\vskip\strutdp + \verticalstrut + \vskip-\struttotal}% + \fi}}% + \let\tabulatepass\plustwo + % + \ifcase\tabulaterepeathead + \ifinsidesplitfloat + \setbox\tabulatebox\vbox \bgroup + \else + \startframedcontent[\tabulateparameter\c!frame]% + \fi + \else + \setbox\tabulatebox\vbox \bgroup + \fi + % + \@EA\halign\@EA{\the\!!toksa\crcr\fulltabulatecontent\crcr}% + \prevdepth\strutdp % nog eens beter, temporary hack + \doifvalue{\??tt\currenttabulate\c!distance}\v!grid + {\vskip-\strutdp}% experimental tm-prikkels + % + \ifcase\tabulaterepeathead + \ifinsidesplitfloat + \egroup \splittabulatebox\tabulatebox + \else + \stopframedcontent + \fi + \else + \egroup \splittabulatebox\tabulatebox + \fi + % + \egroup + \ifinsidefloat \else + \tabulateparameter\c!after + \fi + \egroup} + +\egroup + +% \setuptabulate[split=yes,header=text,title=Vervolg van Tabel] +% +% % \starttabulatehead +% % \NC test \NC hans\NC \NR +% % \stoptabulatehead +% +% \starttabulate +% \NC test \NC \input tufte \relax \NC \NR +% \NC test \NC \input knuth \relax \NC \NR +% \NC test \NC \input knuth \relax \NC \NR +% \NC test \NC \input tufte \relax \NC \NR +% \NC test \NC \input tufte \relax \NC \NR +% \NC test \NC \input tufte \relax \NC \NR +% \stoptabulate + +% \def\splittabulatebox#1% #1 <> 0/2 / derived from the one in core-ntb.tex +% {\ifinsidefloat +% \unvbox#1% +% \else +% \ifcase\tabulaterepeathead\or +% \setbox2\copy#1% +% \setbox2\vsplit2 to \lineheight +% \setbox2\vbox{\unvbox2}% +% \fi +% \doloop +% {\setbox0\vsplit#1 to \onepoint % \lineheight +% \ifdim\pagegoal<\maxdimen +% \donetrue +% \else\ifdim\pagetotal=\zeropoint +% \donetrue +% \else +% \donefalse +% \fi\fi +% \ifdone +% \setbox0\vbox{\unvbox0}% +% \dimen0\pagetotal +% \advance\dimen0\dp0 +% \advance\dimen0\ht0 +% \ifdim\dimen0>\pagegoal +% \bgroup \page \egroup % make sure that local vars are kept +% \ifcase\tabulaterepeathead\or +% \unvcopy2 +% \or +% \hbox{\strut\tabulateparameter\c!title}% +% \fi +% \fi +% \fi +% % test this on icare checklists / quite hacky ! ! ! +% \ifdim\ht0>\tabulateparameter\c!rulethickness\else +% \kern-2\ht0 % brrrr +% \fi +% % +% \unvbox0 +% \allowbreak +% \ifvoid#1 \exitloop \fi}% +% \fi} + +\def\splittabulatebox#1% #1 <> 0/2 / derived from the one in core-ntb.tex + {\ifinsidesplitfloat + \dosplittabulatebox#1% + \else\ifinsidefloat + \unvbox#1% + \else + \dosplittabulatebox#1% + \fi\fi} + +\def\dosplittabulatebox#1% + {\resettsplit + \def\tsplitminimumfreelines{2}% + \def\tsplitminimumfreespace{0pt}% + \setbox\tsplitcontent\box#1% + \ifcase\tabulaterepeathead\or + \setbox\tsplithead\vsplit\tsplitcontent to \lineheight + \setbox\tsplithead\vbox{\unvbox\tsplithead}% + \or + \setbox\tsplithead\vbox{\hbox{\strut\tabulateparameter\c!title}}% + \fi + \handletsplit} + +%D \starttyping +%D \setuptabulate[split=no,rule=line] +%D +%D \starttabulate +%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule +%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule +%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule +%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule +%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule +%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule +%D \stoptabulate +%D \stoptyping + +% \starttabulatie[|mc|] +% \NC \digits{100.000,00} \NC\NR +% \NC \digits{@10.000,00} \NC\NR +% \NC \digits{@@@.100,00} \NC\NR +% \NC \digits{@@@.@10,@@} \NC\NR +% \NC \digits{@@@.@@1,@@} \NC\NR +% \stoptabulatie +% +% \starttabulatie[|mc|] +% \ND 100.000,00 \NC\NR +% \ND @10.000,00 \NC\NR +% \ND @@@.100,00 \NC\NR +% \ND @@@.@10,@@ \NC\NR +% \ND @@@.@@1,@@ \NC\NR +% \stoptabulatie +% +% \starttabulatie[|c|] +% \ND $100.000,00$ \NC\NR +% \ND $@10.000,00$ \NC\NR +% \ND $@@@.100,00$ \NC\NR +% \ND $@@@.@10,@@$ \NC\NR +% \ND $@@@.@@1,@@$ \NC\NR +% \stoptabulatie +% +% \starttabulatie[|c|] +% \NC $\digits 100.000,00 $ \NC\NR +% \NC $\digits @10.000,00 $ \NC\NR +% \NC $\digits @@@.100,00 $ \NC\NR +% \NC $\digits @@@.@10,@@ $ \NC\NR +% \NC $\digits @@@.@@1,@@ $ \NC\NR +% \stoptabulatie +% +% \starttabulatie[|c|] +% \NC \digits $100.000,00$ \NC\NR +% \NC \digits $@10.000,00$ \NC\NR +% \NC \digits $@@@.100,00$ \NC\NR +% \NC \digits $@@@.@10,@@$ \NC\NR +% \NC \digits $@@@.@@1,@@$ \NC\NR +% \stoptabulatie + +\def\setuptabulate + {\dotripleempty\dosetuptabulate} + +\def\dosetuptabulate[#1][#2][#3]% + {\ifthirdargument + \getparameters[\??tt#1::#2][#3]% + \else\ifsecondargument + \getparameters[\??tt#1::][#2]% + \else + \getparameters[\??tt\v!tabulate::][#1]% + \fi\fi} + +\setuptabulate + [\c!unit=1em, + EQ={:}, + \c!frame=\v!off, + \c!bodyfont=, + \c!rule=\v!normal, + \c!rulecolor=, + \c!rulethickness=\linewidth, + \c!inner=, + \c!before=\blank, + \c!after=\blank, + \c!distance={\v!depth,\v!medium}, + \c!align=\v!normal, + \c!margin=\!!zeropoint, + \c!split=\v!auto, + \c!header=\v!yes, + \c!title=, + \c!indenting=\v!no] + +\protect \endinput diff --git a/tex/context/base/tabl-tsp.tex b/tex/context/base/tabl-tsp.tex new file mode 100644 index 000000000..49bb7ad90 --- /dev/null +++ b/tex/context/base/tabl-tsp.tex @@ -0,0 +1,427 @@ +%D \module +%D [ file=tabl-tsp, +%D version=2000.10.20, +%D title=\CONTEXT\ Table Macros, +%D subtitle=Splitting, +%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 Table Macros / Splitting} + +%D The code in this file is move here from other places. + +\unprotect + +% only to be used with single tokens (will be prim) + +\ifx\htdp\undefined \def\htdp#1{\dimexpr\ht#1+\dp#1\relax} \fi + +%D Although the name resembles floats, and therefore this should be +%D a page module, we decided to make it core functionality because the +%D table code depends on it. Othrwise there would be too much +%D overloading afterwards involved. Actually, the float part is rather +%D generic and not that related to floats. + +% \splitfloat [settings] {\placetable[optional args]{test}} {content} + +\definenumber + [\??si] + [\c!way=\v!by\v!text, + \c!conversion=\@@siconversion] + +\def\setupfloatsplitting + {\dodoubleargument\getparameters[\??si]} + +\newif\ifinsidesplitfloat % will become chardef + +\newtoks \everysplitfloatsetup + +\def\splitfloat + {\dosingleempty\dosplitfloat} + +\ifx\floatcaptionsuffix\undefined \else + \let\floatcaptionsuffix\empty % will become \splitfloatcaptionsuffix +\fi + +\def\extrasplitfloatlines{0} + +\def\dosplitfloat[#1]#2% nog dubbele refs + {\bgroup + \global\setfalse\splitfloatdone + \aftergroup\checksplitfloat + \insidefloattrue + \insidesplitfloattrue + \getparameters[\??si][#1]% + \resetnumber[\??si]% + \def\floatcaptionsuffix{\convertednumber[\??si]}% + \let\extrasplitfloatlines\@@silines + \the\everysplitfloatsetup + \def\splitfloatcommand{#2}% + \global\settrue \onlyonesplitofffloat + \global\setfalse\somenextplitofffloat + \dopushsavedfloats + \@@sibefore + \let\next} % \bgroup + +\def\checksplitfloat + {\ifconditional\splitfloatdone\else + \blank{\tttf \getmessage\m!floatblocks{13}\empty}\blank + \showmessage\m!floatblocks{13}\empty + \fi} + +\settrue \onlyonesplitofffloat +\setfalse\somenextplitofffloat + +%D When \type {inbetween} is made empty instead of the +%D default \type {\page}, we will get delayed flushing +%D and text may continue below the graphic. +%D +%D \starttyping +%D \dorecurse{2}{\input tufte } +%D +%D \splitfloat[lines=auto,inbetween=] +%D {\placetable{\dorecurse{5}{test\recurselevel\endgraf}}} +%D {\bTABLE[split=yes] +%D \bTR \bTD 11 \eTD \bTD \input tufte \eTD \eTR +%D \bTR \bTD 12 \eTD \bTD \input zapf \eTD \eTR +%D \bTR \bTD 13 \eTD \bTD \input bryson \eTD \eTR +%D \bTR \bTD 14 \eTD \bTD test \eTD \eTR +%D \bTR \bTD 21 \eTD \bTD \input tufte \eTD \eTR +%D \bTR \bTD 22 \eTD \bTD \input zapf \eTD \eTR +%D \bTR \bTD 23 \eTD \bTD \input bryson \eTD \eTR +%D \bTR \bTD 24 \eTD \bTD test \eTD \eTR +%D \bTR \bTD 31 \eTD \bTD \input tufte \eTD \eTR +%D \bTR \bTD 32 \eTD \bTD \input zapf \eTD \eTR +%D \bTR \bTD 33 \eTD \bTD \input bryson \eTD \eTR +%D \bTR \bTD 34 \eTD \bTD test \eTD \eTR +%D \eTABLE} +%D +%D \dorecurse{10}{\input tufte } +%D \stoptyping + +\newconditional\splitfloatdone + +\def\dodowithsplitofffloat + {\dowithnextbox + {\forgetall + \dontcomplain + \global\settrue\splitfloatdone + \chardef\nodelocationmode\zerocount % bypass auto-renumbering + \incrementnumber[\??si]% + \ifcase\rawnumber[\??si]\or \ifconditional\onlyonesplitofffloat + \let\floatcaptionsuffix\empty + \fi \fi + \bgroup + \ifconditional\somenextplitofffloat + \settrue\retainfloatnumber +\notesenabledfalse % best here, experimental, brrr; test with note in caption + \else + \setfalse\retainfloatnumber + \fi + \splitfloatcommand{\box\nextbox}% + \egroup + \ifconditional\somenextplitofffloat + \doifelsenothing\@@siinbetween + {\ifconditional\splitfloatfirstdone\else\page\fi} + \@@siinbetween + \else + \@@siafter + \dopopsavedfloats + \doflushsavedfloats + \fi + \global\settrue\splitfloatfirstdone}% + \vbox} + +\def\nodowithsplitofffloat + {\dowithnextbox + {\forgetall + \dontcomplain + \box\nextbox % maybe an option to unvbox + \global\settrue\splitfloatfirstdone}% + \vbox} + +\def\dochecksplitofffloat#1% box + {\ifinsidesplitfloat + \ifdim\ht#1=\zeropoint + \global\setfalse\somenextplitofffloat + \else + \global\settrue \somenextplitofffloat + \global\setfalse\onlyonesplitofffloat + \fi + \fi} + +\def\analyzesplitfloatcaption#1% depends on page-flt + {\doif\extrasplitfloatlines\v!auto + {\bgroup + \settrue\retainfloatnumber + \chardef\nodelocationmode\zerocount + \forcelocalfloats + \setuplocalfloats[\c!before=,\c!after=,\c!inbetween=]% + \splitfloatcommand{\hbox to \wd#1{\strut}}% dummy line + \setbox\scratchbox\vbox{\flushlocalfloats}% + \getnoflines{\ht\scratchbox}% + \resetlocalfloats + \advance\noflines\minusone % compensate dummy line + \expanded{\egroup\noexpand\edef\noexpand\extrasplitfloatlines{\the\noflines}}}} + +% \def\analyzesplitfloatcaption#1% +% {\edef\extrasplitfloatlines{11}} + +\def\dowithsplitofffloat % nextbox + {\ifinsidesplitfloat + \expandafter\dodowithsplitofffloat + \else + \expandafter\nodowithsplitofffloat + \fi} + +\def\doifnotinsidesplitfloat + {\ifinsidesplitfloat\expandafter\gobbleoneargument\fi} + +%D Some defaults: + +\setupfloatsplitting + [\c!conversion=\v!character, % \v!romannumerals + \c!lines=3, + \c!before=, + \c!inbetween=\page, + \c!after=] + +%D Table splitter, on top of previous code: + +\newbox\tsplitcontent +\newbox\tsplitresult +\newbox\tsplithead +\newbox\tsplitnext +\newbox\tsplittail + +\def\resettsplit{% only \def's starting a a new line are seen by the dep checker + \def\tsplitminimumfreelines{0}% + \def\tsplitminimumfreespace{0pt}% + \setbox\tsplitcontent \vbox{}% + \setbox\tsplitresult \vbox{}% + \setbox\tsplithead \vbox{}% + \setbox\tsplitnext \vbox{}% + \setbox\tsplittail \vbox{}% + \let\tsplitbeforeresult\donothing + \let\tsplitafterresult \donothing + \let\tsplitinbetween \donothing + \let\tsplitbefore \donothing + \let\tsplitafter \donothing + \let\postprocesstsplit \donothing +} + +\resettsplit + +% todo: keep tail to rest, so we need a lookahead + +\newconditional\splitfloatfirstdone + +\def\handletsplit + {\analyzesplitfloatcaption\tsplitcontent + \global\setfalse\splitfloatfirstdone + \testpagesync % new, sync, but still tricky + [\tsplitminimumfreelines] + [\dimexpr\tsplitminimumfreespace+\extrasplitfloatlines\lineheight\relax]% + \setbox\scratchbox\vbox{\tsplitinbetween}% + \edef\tsplitinbetweenheight{\the\htdp\scratchbox}% etex + \!!doneafalse + \doloop + {\ifinsidecolumns + % brrr, assumes empty columns + \global\setfalse\splitfloatfirstdone + \scratchdimen\textheight + \!!donectrue + \else + \ifconditional\splitfloatfirstdone + \scratchdimen\textheight + \!!donectrue + \else\ifdim\pagegoal<\maxdimen + \scratchdimen\dimexpr\pagegoal-\pagetotal\relax + \!!donecfalse + \else + \scratchdimen\textheight + \!!donectrue + \fi\fi + \fi + \scratchdimen\dimexpr\scratchdimen-\tsplitinbetweenheight-\tsplitminimumfreespace-\extrasplitfloatlines\lineheight\relax + \ifdim\htdp\tsplittail>\zeropoint + \advance\scratchdimen-\htdp\tsplittail + \fi + \setbox\tsplitresult\vbox + {\ifdim\ht\tsplithead>\zeropoint + \unvcopy\tsplithead + \tsplitinbetween + \fi}% + \if!!donea\else\ifdim\ht\tsplitnext>\zeropoint + \setbox\tsplithead\box\tsplitnext + \fi\fi + \!!doneatrue + \ifdim\ht\tsplitresult>\zeropoint + \!!donedtrue % table head + \else + \!!donedfalse % no tablehead + \fi + \splittopskip\zeropoint + \doloop + {\setbox\scratchbox\vsplit\tsplitcontent to \onepoint % \lineheight + \setbox\scratchbox\vbox{\unvbox\scratchbox}% + \ifdim\dimexpr\scratchdimen-\htdp\scratchbox-\htdp\tsplitresult\relax>\zeropoint + \setbox\tsplitresult\vbox + {\unvbox\tsplitresult + \tsplitinbetween + \unvbox\scratchbox}% + \ifvoid\tsplitcontent \exitloop \fi + \else\if!!doned + % we only have a tablehead so far + \setbox\tsplitresult\vbox{\unvbox\tsplitresult\unvbox\scratchbox}% + \exitloop + \else\if!!donec + % we have text height available, but the (one) cell is too + % large to fit, so, in order to avoid loops/deadcycles we do: + \setbox\tsplitresult\vbox + {\unvbox\tsplitresult + \tsplitinbetween + \unvbox\scratchbox}% + \exitloop + \else + \setbox\tsplitcontent\vbox + {\unvbox\scratchbox + \tsplitinbetween + \ifvoid\tsplitcontent\else\unvbox\tsplitcontent\fi}% + \exitloop + \fi\fi\fi + \!!donedfalse + \!!donecfalse}% + \postprocesstsplit + \dochecksplitofffloat\tsplitcontent + \ifvoid\tsplitcontent + \setbox\tsplitresult\vbox + {\unvbox\tsplitresult + \tsplitinbetween + \unvcopy\tsplittail}% + \dowithsplitofffloat{\tsplitbeforeresult\box\tsplitresult\tsplitafterresult}% + \doifnotinsidesplitfloat\tsplitafter + \endgraf + \exitloop + \else + % hack + \ifdim\pagegoal<\maxdimen + \global\pagegoal\dimexpr\pagegoal+\lineheight\relax % etex + \fi + % brrr + \ifdim\ht\tsplitresult>\zeropoint + \setbox\tsplitresult\vbox + {\unvbox\tsplitresult + \tsplitinbetween + \unvcopy\tsplittail}% + \dowithsplitofffloat{\tsplitbeforeresult\box\tsplitresult\tsplitafterresult}% + \doifnotinsidesplitfloat\tsplitafter + \endgraf + \fi + \ifinsidecolumns + \doifnotinsidesplitfloat\goodbreak + \else + \doifnotinsidesplitfloat\page + \fi + \fi}% + \global\setfalse\splitfloatfirstdone} % we can use this one for tests + +\protect \endinput + +% test cases + +% \setupTABLE[split=repeat] +% +% \input tufte \endgraf +% \splitfloat[lines=11] +% {\placetable{\dorecurse{10}{test\recurselevel\endgraf}}} +% {\bTABLE\dorecurse{100}{\bTR \bTD test \eTD \eTR}\eTABLE} +% \input tufte \page +% +% \input tufte \endgraf +% \splitfloat[lines=0] +% {} +% {\bTABLE\dorecurse{100}{\bTR \bTD test \eTD \eTR}\eTABLE} +% \input tufte \endgraf \page +% +% \input tufte \endgraf +% \bTABLE\dorecurse{100}{\bTR \bTD test \eTD \eTR}\eTABLE +% \input tufte \page + +% \setuptabulate[split=yes] +% +% \input tufte \endgraf +% \splitfloat[lines=11] +% {\placetable{\dorecurse{10}{test\recurselevel\endgraf}}} +% {\starttabulate\dorecurse{200}{\NC test \NC test \NC \NR}\stoptabulate} +% \input tufte \page +% +% \input tufte \endgraf +% \splitfloat[lines=0] +% {} +% {\starttabulate\dorecurse{200}{\NC test \NC test \NC \NR}\stoptabulate} +% \input tufte \page +% +% \input tufte \endgraf +% \starttabulate\dorecurse{200}{\NC test \NC test \NC \NR}\stoptabulate +% \input tufte \page + +% \setuptables[split=yes] +% +% \newtoks\TestToks +% +% \TestToks\emptytoks +% \appendtoks\starttablehead\to\TestToks +% \dorecurse{3}{\appendtoks\VL head \VL head \VL \SR\to\TestToks} +% \appendtoks\stoptablehead\to\TestToks +% \appendtoks\starttabletail\to\TestToks +% \dorecurse{3}{\appendtoks\VL tail \VL tail \VL \SR\to\TestToks} +% \appendtoks\stoptabletail\to\TestToks +% \appendtoks\starttables[|c|c|]\to\TestToks +% \dorecurse{100}{\appendtoks\VL test \VL test \VL \SR\to\TestToks} +% \appendtoks\stoptables\to\TestToks +% +% \input tufte \endgraf +% \splitfloat[lines=auto] % [lines=11] +% {\placetable{\dorecurse{10}{test\recurselevel\endgraf}}} +% {\the\TestToks} +% \input tufte \page +% +% \input tufte \endgraf +% \splitfloat[lines=0] +% {} +% {\the\TestToks} +% \input tufte \page +% +% \input tufte \endgraf +% \the\TestToks +% \input tufte \page +% +% multiple floats +% +% \starttext +% \dorecurse{3}{\input tufte } \endgraf +% \dorecurse{5}{\placefigure{}{\framed[height=.5\textheight]{}}} +% \splitfloat[lines=auto,inbetween=] +% {\placetable{\dorecurse{5}{test\recurselevel\endgraf}}} +% {\bTABLE[split=yes] +% \bTR \bTD 11 \eTD \bTD \input tufte \eTD \eTR +% \bTR \bTD 12 \eTD \bTD \input zapf \eTD \eTR +% \bTR \bTD 13 \eTD \bTD \input bryson \eTD \eTR +% \bTR \bTD 14 \eTD \bTD test \eTD \eTR +% \bTR \bTD 21 \eTD \bTD \input tufte \eTD \eTR +% \bTR \bTD 22 \eTD \bTD \input zapf \eTD \eTR +% \bTR \bTD 23 \eTD \bTD \input bryson \eTD \eTR +% \bTR \bTD 24 \eTD \bTD test \eTD \eTR +% \bTR \bTD 31 \eTD \bTD \input tufte \eTD \eTR +% \bTR \bTD 32 \eTD \bTD \input zapf \eTD \eTR +% \bTR \bTD 33 \eTD \bTD \input bryson \eTD \eTR +% \bTR \bTD 34 \eTD \bTD test \eTD \eTR +% \eTABLE} +% \dorecurse{10}{\input tufte } +% \stoptext 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 spans the next 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-- -

This code is experimental.

+

This code is experimental and needs a cleanup. The visualizers will move to +a module.

--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/trac-deb.lua b/tex/context/base/trac-deb.lua new file mode 100644 index 000000000..f476169c3 --- /dev/null +++ b/tex/context/base/trac-deb.lua @@ -0,0 +1,206 @@ +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 lmx then lmx = { } end +if not lmx.variables then lmx.variables = { } 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-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 + +tracers.strings.undefined = "undefined" + +function tracers.split(csname) + return csname:match("^(.+):(.+)$") +end + +function tracers.type(csname) + tag, name = tracers.split(csname) + if tag then return tag else return nil end +end + +function tracers.name(csname) + tag, name = tracers.split(csname) + if tag then return name else return csname end +end + +function tracers.cs(csname) + tag, name = tracers.split(csname) + if tracers.types[tag] then + return tracers.types[tag](name) + else + return tracers.primitive(csname) + end +end + +function tracers.dimen(name) + return (tex.dimen[name] and number.topoints(tex.dimen[name])) or tracers.strings.undefined +end + +function tracers.count(name) + return tex.count[name] or tracers.strings.undefined +end + +function tracers.toks(name) + return (tex.toks[name] and string.limit(tex.toks[name],40)) or tracers.strings.undefined +end + +function tracers.primitive(name) + return tex[name] or tracers.strings.undefined +end + +tracers.types = { + ['d'] = tracers.dimen, + ['c'] = tracers.count, + ['t'] = tracers.toks, + ['p'] = tracers.primitive +} + +function tracers.knownlist(name) + return tracers.list[name] and #tracers.list[name] > 0 +end + +function tracers.showdebuginfo() + lmx.set('title', 'ConTeXt Debug Information') + lmx.set('color-background-one', lmx.get('color-background-green')) + lmx.set('color-background-two', lmx.get('color-background-blue')) + lmx.show('context-debug.lmx') + lmx.restore() +end + +function tracers.showerror() + lmx.set('title', 'ConTeXt Error Information') + lmx.set('errormessage', status.lasterrorstring) + lmx.set('linenumber', status.linenumber) + lmx.set('color-background-one', lmx.get('color-background-yellow')) + lmx.set('color-background-two', lmx.get('color-background-purple')) + local filename = status.filename + local linenumber = tonumber(status.linenumber or "0") + if not filename then + lmx.set('filename', 'unknown') + lmx.set('errorcontext', 'error in filename') + elseif type(filename) == "number" then + lmx.set('filename', "") + lmx.set('errorcontext', 'unknown error') + elseif io.exists(filename) then + -- todo: use an input opener so that we also catch utf16 an reencoding + lmx.set('filename', filename) + lines = io.lines(filename) + if lines then + local context = { } + n, m = 1, linenumber + b, e = m-10, m+10 + s = string.len(tostring(e)) + for line in lines do + if n > e then + break + elseif n > b then + if n == m then + context[#context+1] = string.format("%" .. s .. "d",n) .. " >> " .. line + else + context[#context+1] = string.format("%" .. s .. "d",n) .. " " .. line + end + end + n = n + 1 + end + lmx.set('errorcontext', table.concat(context,"\n")) + else + lmx.set('errorcontext', "") + end + else + lmx.set('filename', filename) + lmx.set('errorcontext', 'file not found') + end + lmx.show('context-error.lmx') + lmx.restore() +end + +function tracers.overloaderror() + callback.register('show_error_hook', tracers.showerror) +end + +tracers.list['scratch'] = { + 0, 2, 4, 6, 8 +} + +tracers.list['internals'] = { + 'p:hsize', 'p:parindent', 'p:leftskip','p:rightskip', + 'p:vsize', 'p:parskip', 'p:baselineskip', 'p:lineskip', 'p:topskip' +} + +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/trac-deb.tex b/tex/context/base/trac-deb.tex new file mode 100644 index 000000000..870c452ad --- /dev/null +++ b/tex/context/base/trac-deb.tex @@ -0,0 +1,43 @@ +%D \module +%D [ file=trac-deb, +%D version=2005.11.06, +%D title=\CONTEXT\ Tracing Macros, +%D subtitle=Debugger, +%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 Tracing Macros / Debugger} + +\registerctxluafile{trac-deb}{1.001} + +\def\showdebuginfo{\ctxlua{tracers.showdebuginfo()}} +\def\overloaderror{\ctxlua{tracers.overloaderror()}} + +\def\breakpoint{\showdebuginfo\wait} + +\appendtoks + \ctxlua { + if debugger.tracing() then + debugger.enable() ; + end + }% +\to \everyjob + +\appendtoks + \ctxlua { + if debugger.tracing() then + debugger.disable() ; + debugger.savestats("\jobname-luacalls.log") ; + end + }% +\to \everybye + +\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/trac-lmx.lua b/tex/context/base/trac-lmx.lua new file mode 100644 index 000000000..07f5ae291 --- /dev/null +++ b/tex/context/base/trac-lmx.lua @@ -0,0 +1,158 @@ +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" +} + +local gsub, format, concat = string.gsub, string.format, table.concat + +-- we can now use l-xml, and we can also use lpeg + +lmx = lmx or { } + +lmx.escapes = { + ['&'] = '&', + ['<'] = '<', + ['>'] = '>', + ['"'] = '"' +} + +-- local function p -> ends up in lmx.p, so we need to cast + +lmx.variables = { } + +lmx.variables['title-default'] = 'LMX File' +lmx.variables['title'] = lmx.variables['title-default'] + +-- demonstrates: local, *all, gsub using tables, nil or value, loadstring + +function lmx.loadedfile(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 = 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) + str = tostring(str) + str = gsub(str,'&','&') + str = gsub(str,'[<>"]',lmx.escapes) + return str + end + function lmx.type(str) + if str then lmx.print("" .. lmx.escape(str) .. "") end + end + function lmx.pv(str) + lmx.print(lmx.variable(str)) + end + function lmx.tv(str) + lmx.type(lmx.variable(str)) + end + data = gsub(data,"<%?lmx%-include%s+(.-)%s-%?>", function(filename) + return lmx.loadedfile(filename) + end) + local definitions = { } + data = gsub(data,"<%?lmx%-define%-begin%s+(%S-)%s-%?>(.-)<%?lmx%-define%-end%s-%?>", function(tag,content) + definitions[tag] = content + return "" + end) + data = gsub(data,"<%?lmx%-resolve%s+(%S-)%s-%?>", function(tag) + return definitions[tag] or "" + end) + data = gsub(data,"%c%s-(<%?lua .-%?>)%s-%c", function(lua) + return "\n" .. lua .. " " + end) + data = gsub(data .. "","(.-)<%?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 + 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 + +if os.platform == "windows" then + lmx.popupfile = function(filename) os.execute("start " .. filename) end +else + lmx.popupfile = function(filename) os.execute(filename) end +end + +function lmx.make(name) + local lmxfile = lmx.lmxfile(name) + local htmfile = lmx.htmfile(name) + if lmxfile == htmfile then + 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 + +lmx.restorables = { } + +function lmx.set(key, value) + if not lmx.restorables[key] then + table.insert(lmx.restorables, key) + lmx.variables['@@' .. key] = lmx.variables[key] + end + lmx.variables[key] = value +end + +function lmx.get(key) + return lmx.variables[key] or "" +end + +function lmx.restore() + for _,key in pairs(lmx.restorables) do + lmx.variables[key] = lmx.variables['@@' .. key] + end + lmx.restorables = { } +end + +-- command line + +if arg then + if arg[1] == "--show" then if arg[2] then lmx.show (arg[2]) end + elseif arg[1] == "--convert" then if arg[2] then lmx.convert(arg[2], arg[3] or "temp.html") end + end +end diff --git a/tex/context/base/trac-lmx.tex b/tex/context/base/trac-lmx.tex new file mode 100644 index 000000000..a47d2b8bb --- /dev/null +++ b/tex/context/base/trac-lmx.tex @@ -0,0 +1,16 @@ +%D \module +%D [ file=trac-lmx, +%D version=2005.09.02, +%D title=\CONTEXT\ Tracing Macros, +%D subtitle=LMX, +%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 Tracing Macros / LMX} + +\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-- +

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 structured file. Actually, any logging that +is hooked into callbacks will be \XML\ by default.

+--ldx]]-- + +logs = logs or { } +logs.xml = logs.xml or { } +logs.tex = logs.tex or { } + +--[[ldx-- +

This looks pretty ugly but we need to speed things up a bit.

+--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("%s",category,format(fmt,...))) + else + write_nl(format("",category)) + end +end +function logs.xml.line(fmt,...) -- new + if fmt then + write_nl(format("%s",format(fmt,...))) + else + write_nl("") + 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("") end end +function logs.xml.push () if logs.level > 0 then tw("" ) end end + +function logs.xml.start_run() + write_nl("") + write_nl("") -- xmlns='www.pragma-ade.com/luatex/schemas/context-job.rng' + write_nl("") +end + +function logs.xml.stop_run() + write_nl("") +end + +function logs.xml.start_page_number() + write_nl(format("

") + write_nl("") +end + +function logs.xml.report_output_pages(p,b) + write_nl(format("", p)) + write_nl(format("", b)) + write_nl("") +end + +function logs.xml.report_output_log() +end + +function logs.xml.report_tex_stat(k,v) + texiowrite_nl("log",""..tostring(v).."") +end + +local level = 0 + +function logs.xml.show_open(name) + level = level + 1 + texiowrite_nl(format("",level,name)) +end + +function logs.xml.show_close(name) + texiowrite(" ") + level = level - 1 +end + +function logs.xml.show_load(name) + texiowrite_nl(format("",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: + 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/trac-tra.lua b/tex/context/base/trac-tra.lua new file mode 100644 index 000000000..8a51d33b9 --- /dev/null +++ b/tex/context/base/trac-tra.lua @@ -0,0 +1,221 @@ +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 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 '' + 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 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.mkii b/tex/context/base/type-ini.mkii new file mode 100644 index 000000000..fa7b7934f --- /dev/null +++ b/tex/context/base/type-ini.mkii @@ -0,0 +1,743 @@ +%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 tmf] +\usetypescriptfile[\f!typeprefix siz] + +\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 +\fi + +\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 {\chardef\typescriptmethod\plusone\dotripleempty\dousetypescript} +\unexpanded\def\usetypescriptexact{\chardef\typescriptmethod\plustwo\dotripleempty\dousetypescript} + +\def\dousetypescript[#1][#2][#3]% + {\expanded{\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 \chardef\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} + +\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 + \long\def\starttypescript##1\stoptypescript + {\global\loadedtypescripts\@EA{\the\loadedtypescripts\starttypescript##1\stoptypescript}}% + \long\def\starttypescriptcollection##1\stoptypescriptcollection + {\global\loadedtypescripts\@EA{\the\loadedtypescripts\starttypescriptcollection##1\stoptypescriptcollection}}% + \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}% + \expanded{\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\else\donefalse\fi + \else\ifx#1\typescript@@all + \donetrue + \else\ifx\@@typescriptcheck\typescript@@all + \donetrue + \else\expanded{\doifcommonelse{\@@typescriptcheck}{#1}}\donetrue\donefalse\ifdone + \let#2\commalistelement + \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]{\expanded{\processcommalist[#1]}\dopreloadmapfile} +\def\loadmapfile [#1]{\expanded{\processcommalist[#1]}\loadthemapfile} +\def\unloadmapfile [#1]{\expanded{\processcommalist[#1]}\unloadthemapfile} + +% too soon, no driver known, \ifproductionrun \loadallfontmapfiles \fi + +% temp hack, will become just \addto + +\ifx\pdftexversion\undefined + + \def\loadthemapfile#1% + {\splitfiletype{#1}% + \doglobal\addtocommalist\splitoffname\allfontmapsfiles} + +\else\ifnum\pdftexversion<120 % no overloading + + \def\loadthemapfile#1% + {\splitfiletype{#1}% + \doglobal\pretocommalist\splitoffname\allfontmapsfiles} + +\else + + \def\loadthemapfile#1% + {\splitfiletype{#1}% + \doglobal\addtocommalist\splitoffname\allfontmapsfiles} + +\fi \fi + +\def\unloadthemapfile#1% + {\splitfiletype{#1}% + \doglobal\removefromcommalist\splitoffname\allfontmapsfiles} + +\let\usedmapfile\gobbletwoarguments +\let\usedmapline\gobbletwoarguments + +\def\doregisterloadedmapfile#1% + {\immediatewriteutilitycommand{\usedmapfile{=}{#1}}} + +\def\doloadfontmapfile#1% + {\ifundefined{#1\c!state}% + \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% + {\ifundefined{#1\c!state}% + \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 + \expanded{\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][#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 + +% old and obsolete +% +% \def\doreadfontdefinitionfile#1#2% #1 = set/switch state +% {\ifundefined{\??tf#2\c!default}% +% \pushmacro\fontclass +% \setcurrentfontclass\empty +% \pushmacro\@@typescriptone \edef\@@typescriptone {\truetypescript{#2}}% +% \pushmacro\@@typescripttwo \let\@@typescripttwo \empty +% \pushmacro\@@typescriptthree\let\@@typescriptthree\empty +% \typescriptfoundfalse +% \dododousetypescript{\f!typeprefix pre}% +% \popmacro\@@typescriptthree +% \popmacro\@@typescripttwo +% \popmacro\@@typescriptone +% \iftypescriptfound \else +% \normaldoreadfontdefinitionfile{#1}{#2}% +% \fi +% \setcurrentfontclass\empty +% \popmacro\fontclass +% \else\ifcase#1\relax +% \switchtotypeface[#2]% +% \else +% \setuptypeface[#2]% +% \fi\fi} +% +% new and obeying fontclasses (but still obsolete) + +\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} + +% \usetypescript [berry] [ec] + +\protect \endinput 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-ini.tex b/tex/context/base/type-ini.tex deleted file mode 100644 index 17b1c2088..000000000 --- a/tex/context/base/type-ini.tex +++ /dev/null @@ -1,721 +0,0 @@ -%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 (ini)} - -%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 -% -% \beginXETEX \font -% \usetypescriptfile[\f!typeprefix xtx] % xetex definitions -% \endXETEX - -\usetypescriptfile[\f!typeprefix tmf] -\usetypescriptfile[\f!typeprefix siz] - -\beginOLDTEX \font - \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 - -\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 {\chardef\typescriptmethod\plusone\dotripleempty\dousetypescript} -\unexpanded\def\usetypescriptexact{\chardef\typescriptmethod\plustwo\dotripleempty\dousetypescript} - -\def\dousetypescript[#1][#2][#3]% - {\expanded{\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 \chardef\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} - -\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 - \long\def\starttypescript##1\stoptypescript - {\global\loadedtypescripts\@EA{\the\loadedtypescripts - \starttypescript##1\stoptypescript}}% - \long\def\starttypescriptcollection##1\stoptypescriptcollection - {\global\loadedtypescripts\@EA{\the\loadedtypescripts - \starttypescriptcollection##1\stoptypescriptcollection}}% - \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}% - \expanded{\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 - \doifnextcharelse[\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 - {\doifnextcharelse[\dostarttypescripttwo\dostarttypescriptyes} - -\long\def\redostarttypescripttwo - {\doifnextcharelse[\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\else\donefalse\fi - \else\ifx#1\typescript@@all - \donetrue - \else\ifx\@@typescriptcheck\typescript@@all - \donetrue - \else\expanded{\doifcommonelse{\@@typescriptcheck}{#1}}\donetrue\donefalse\ifdone - \let#2\commalistelement - \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]{\expanded{\processcommalist[#1]}\dopreloadmapfile} -\def\loadmapfile [#1]{\expanded{\processcommalist[#1]}\loadthemapfile} -\def\unloadmapfile [#1]{\expanded{\processcommalist[#1]}\unloadthemapfile} - -% too soon, no driver known, \ifproductionrun \loadallfontmapfiles \fi - -% temp hack, will become just \addto - -\ifx\pdftexversion\undefined - - \def\loadthemapfile#1% - {\splitfiletype{#1}% - \doglobal\addtocommalist\splitoffname\allfontmapsfiles} - -\else\ifnum\pdftexversion<120 % no overloading - - \def\loadthemapfile#1% - {\splitfiletype{#1}% - \doglobal\pretocommalist\splitoffname\allfontmapsfiles} - -\else - - \def\loadthemapfile#1% - {\splitfiletype{#1}% - \doglobal\addtocommalist\splitoffname\allfontmapsfiles} - -\fi \fi - -\def\unloadthemapfile#1% - {\splitfiletype{#1}% - \doglobal\removefromcommalist\splitoffname\allfontmapsfiles} - -\let\usedmapfile\gobbletwoarguments -\let\usedmapline\gobbletwoarguments - -\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}% - \doregisterloadedmapfile{#1}% - \doloadmapfile{=}{#1.\f!fontmapextension}% +/add =/replace -/remove - \setxvalue{#1\c!state}{1}% - \fi} - -\def\doreportfontmapfile#1% - {\ifundefined{#1\c!state}% - \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]% - {\setvalue{\??ts::#1}{#2}} - -% 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 - \expanded{\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][#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} - -% 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]}}}} - -\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 - -% old and obsolete -% -% \def\doreadfontdefinitionfile#1#2% #1 = set/switch state -% {\ifundefined{\??tf#2\c!default}% -% \pushmacro\fontclass -% \setcurrentfontclass\empty -% \pushmacro\@@typescriptone \edef\@@typescriptone {\truetypescript{#2}}% -% \pushmacro\@@typescripttwo \let\@@typescripttwo \empty -% \pushmacro\@@typescriptthree\let\@@typescriptthree\empty -% \typescriptfoundfalse -% \dododousetypescript{\f!typeprefix pre}% -% \popmacro\@@typescriptthree -% \popmacro\@@typescripttwo -% \popmacro\@@typescriptone -% \iftypescriptfound \else -% \normaldoreadfontdefinitionfile{#1}{#2}% -% \fi -% \setcurrentfontclass\empty -% \popmacro\fontclass -% \else\ifcase#1\relax -% \switchtotypeface[#2]% -% \else -% \setuptypeface[#2]% -% \fi\fi} -% -% new and obeying fontclasses (but still obsolete) - -\def\doreadfontdefinitionfile#1#2% #1 = set/switch state - {\ifundefined{\??tf#2\c!default}% - \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 - \else\ifcase#1\relax - \switchtotypeface[#2]% - \else - \setuptypeface[#2]% - \fi\fi} - -\fetchruntimecommand \typetypescript {\f!typeprefix\s!run} - -% \usetypescript [berry] [ec] - -\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(">")/">" + P("<")/"<") * space local compareop = P("<") + P("=") + P(">") + P(">=") + P("<=") + P(">") + P("<") 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(">")/">" + P("<")/"<") * 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 @@ - + - + @@ -463,7 +463,7 @@ - + @@ -4096,7 +4096,7 @@ - + @@ -5647,6 +5647,10 @@ + + + + @@ -7083,6 +7087,8 @@ + + @@ -9986,7 +9992,7 @@ - + @@ -9997,7 +10003,7 @@ - + @@ -10014,7 +10020,7 @@ - + @@ -10056,7 +10062,7 @@ - + @@ -10098,7 +10104,7 @@ - + @@ -10138,7 +10144,7 @@ - + @@ -10152,7 +10158,7 @@ - + @@ -10180,7 +10186,7 @@ - + @@ -10199,7 +10205,7 @@ - + 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 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 @@ - + - + @@ -463,7 +463,7 @@ - + @@ -4096,7 +4096,7 @@ - + @@ -5647,6 +5647,10 @@ + + + + @@ -7083,6 +7087,8 @@ + + @@ -9986,7 +9992,7 @@ - + @@ -9997,7 +10003,7 @@ - + @@ -10014,7 +10020,7 @@ - + @@ -10056,7 +10062,7 @@ - + @@ -10098,7 +10104,7 @@ - + @@ -10138,7 +10144,7 @@ - + @@ -10152,7 +10158,7 @@ - + @@ -10180,7 +10186,7 @@ - + @@ -10199,7 +10205,7 @@ - + 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 @@ - + - + @@ -463,7 +463,7 @@ - + @@ -4096,7 +4096,7 @@ - + @@ -5647,6 +5647,10 @@ + + + + @@ -7083,6 +7087,8 @@ + + @@ -9986,7 +9992,7 @@ - + @@ -9997,7 +10003,7 @@ - + @@ -10014,7 +10020,7 @@ - + @@ -10056,7 +10062,7 @@ - + @@ -10098,7 +10104,7 @@ - + @@ -10138,7 +10144,7 @@ - + @@ -10152,7 +10158,7 @@ - + @@ -10180,7 +10186,7 @@ - + @@ -10199,7 +10205,7 @@ - + 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 @@ - + - + @@ -463,7 +463,7 @@ - + @@ -4096,7 +4096,7 @@ - + @@ -5647,6 +5647,10 @@ + + + + @@ -7083,6 +7087,8 @@ + + @@ -9986,7 +9992,7 @@ - + @@ -9997,7 +10003,7 @@ - + @@ -10014,7 +10020,7 @@ - + @@ -10056,7 +10062,7 @@ - + @@ -10098,7 +10104,7 @@ - + @@ -10138,7 +10144,7 @@ - + @@ -10152,7 +10158,7 @@ - + @@ -10180,7 +10186,7 @@ - + @@ -10199,7 +10205,7 @@ - + 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 @@ - + - + @@ -463,7 +463,7 @@ - + @@ -4096,7 +4096,7 @@ - + @@ -5647,6 +5647,10 @@ + + + + @@ -7083,6 +7087,8 @@ + + @@ -9986,7 +9992,7 @@ - + @@ -9997,7 +10003,7 @@ - + @@ -10014,7 +10020,7 @@ - + @@ -10056,7 +10062,7 @@ - + @@ -10098,7 +10104,7 @@ - + @@ -10138,7 +10144,7 @@ - + @@ -10152,7 +10158,7 @@ - + @@ -10180,7 +10186,7 @@ - + @@ -10199,7 +10205,7 @@ - + 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 @@ - + - + @@ -463,7 +463,7 @@ - + @@ -4096,7 +4096,7 @@ - + @@ -5647,6 +5647,10 @@ + + + + @@ -7083,6 +7087,8 @@ + + @@ -9986,7 +9992,7 @@ - + @@ -9997,7 +10003,7 @@ - + @@ -10014,7 +10020,7 @@ - + @@ -10056,7 +10062,7 @@ - + @@ -10098,7 +10104,7 @@ - + @@ -10138,7 +10144,7 @@ - + @@ -10152,7 +10158,7 @@ - + @@ -10180,7 +10186,7 @@ - + @@ -10199,7 +10205,7 @@ - + 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 @@ - + - + @@ -463,7 +463,7 @@ - + @@ -4096,7 +4096,7 @@ - + @@ -5647,6 +5647,10 @@ + + + + @@ -7083,6 +7087,8 @@ + + @@ -9986,7 +9992,7 @@ - + @@ -9997,7 +10003,7 @@ - + @@ -10014,7 +10020,7 @@ - + @@ -10056,7 +10062,7 @@ - + @@ -10098,7 +10104,7 @@ - + @@ -10138,7 +10144,7 @@ - + @@ -10152,7 +10158,7 @@ - + @@ -10180,7 +10186,7 @@ - + @@ -10199,7 +10205,7 @@ - + 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 @@ - + - + @@ -463,7 +463,7 @@ - + @@ -4096,7 +4096,7 @@ - + @@ -5647,6 +5647,10 @@ + + + + @@ -7083,6 +7087,8 @@ + + @@ -9986,7 +9992,7 @@ - + @@ -9997,7 +10003,7 @@ - + @@ -10014,7 +10020,7 @@ - + @@ -10056,7 +10062,7 @@ - + @@ -10098,7 +10104,7 @@ - + @@ -10138,7 +10144,7 @@ - + @@ -10152,7 +10158,7 @@ - + @@ -10180,7 +10186,7 @@ - + @@ -10199,7 +10205,7 @@ - + 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 @@ + @@ -240,6 +241,7 @@ + @@ -298,6 +300,7 @@ + @@ -362,6 +365,7 @@ + @@ -431,6 +435,14 @@ + + + + + + + + @@ -526,6 +538,8 @@ + + @@ -553,6 +567,7 @@ + @@ -599,6 +614,7 @@ + @@ -632,6 +648,7 @@ + @@ -720,9 +737,17 @@ + + + + + + + + @@ -742,8 +767,22 @@ + + + + + + + + + + + + + + @@ -753,6 +792,13 @@ + + + + + + + @@ -763,6 +809,7 @@ + @@ -794,11 +841,18 @@ + + + + + + + @@ -901,6 +955,8 @@ + + @@ -1289,6 +1345,7 @@ + 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 @@ + @@ -240,6 +241,7 @@ + @@ -298,6 +300,7 @@ + @@ -362,6 +365,7 @@ + @@ -431,6 +435,14 @@ + + + + + + + + @@ -526,6 +538,8 @@ + + @@ -553,6 +567,7 @@ + @@ -599,6 +614,7 @@ + @@ -632,6 +648,7 @@ + @@ -720,9 +737,17 @@ + + + + + + + + @@ -742,8 +767,22 @@ + + + + + + + + + + + + + + @@ -753,6 +792,13 @@ + + + + + + + @@ -763,6 +809,7 @@ + @@ -794,11 +841,18 @@ + + + + + + + @@ -901,6 +955,8 @@ + + @@ -1289,6 +1345,7 @@ + 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 @@ + @@ -240,6 +241,7 @@ + @@ -298,6 +300,7 @@ + @@ -362,6 +365,7 @@ + @@ -431,6 +435,14 @@ + + + + + + + + @@ -526,6 +538,8 @@ + + @@ -553,6 +567,7 @@ + @@ -599,6 +614,7 @@ + @@ -632,6 +648,7 @@ + @@ -720,9 +737,17 @@ + + + + + + + + @@ -742,8 +767,22 @@ + + + + + + + + + + + + + + @@ -753,6 +792,13 @@ + + + + + + + @@ -763,6 +809,7 @@ + @@ -794,11 +841,18 @@ + + + + + + + @@ -901,6 +955,8 @@ + + @@ -1289,6 +1345,7 @@ + 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 @@ + @@ -240,6 +241,7 @@ + @@ -298,6 +300,7 @@ + @@ -362,6 +365,7 @@ + @@ -431,6 +435,14 @@ + + + + + + + + @@ -526,6 +538,8 @@ + + @@ -553,6 +567,7 @@ + @@ -599,6 +614,7 @@ + @@ -632,6 +648,7 @@ + @@ -720,9 +737,17 @@ + + + + + + + + @@ -742,8 +767,22 @@ + + + + + + + + + + + + + + @@ -753,6 +792,13 @@ + + + + + + + @@ -763,6 +809,7 @@ + @@ -794,11 +841,18 @@ + + + + + + + @@ -901,6 +955,8 @@ + + @@ -1289,6 +1345,7 @@ + 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 @@ + @@ -240,6 +241,7 @@ + @@ -298,6 +300,7 @@ + @@ -362,6 +365,7 @@ + @@ -431,6 +435,14 @@ + + + + + + + + @@ -526,6 +538,8 @@ + + @@ -553,6 +567,7 @@ + @@ -599,6 +614,7 @@ + @@ -632,6 +648,7 @@ + @@ -720,9 +737,17 @@ + + + + + + + + @@ -742,8 +767,22 @@ + + + + + + + + + + + + + + @@ -753,6 +792,13 @@ + + + + + + + @@ -763,6 +809,7 @@ + @@ -794,11 +841,18 @@ + + + + + + + @@ -901,6 +955,8 @@ + + @@ -1289,6 +1345,7 @@ + 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 @@ + @@ -240,6 +241,7 @@ + @@ -298,6 +300,7 @@ + @@ -362,6 +365,7 @@ + @@ -431,6 +435,14 @@ + + + + + + + + @@ -526,6 +538,8 @@ + + @@ -553,6 +567,7 @@ + @@ -599,6 +614,7 @@ + @@ -632,6 +648,7 @@ + @@ -720,9 +737,17 @@ + + + + + + + + @@ -742,8 +767,22 @@ + + + + + + + + + + + + + + @@ -753,6 +792,13 @@ + + + + + + + @@ -763,6 +809,7 @@ + @@ -794,11 +841,18 @@ + + + + + + + @@ -901,6 +955,8 @@ + + @@ -1289,6 +1345,7 @@ + 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 @@ + @@ -240,6 +241,7 @@ + @@ -298,6 +300,7 @@ + @@ -362,6 +365,7 @@ + @@ -431,6 +435,14 @@ + + + + + + + + @@ -526,6 +538,8 @@ + + @@ -553,6 +567,7 @@ + @@ -599,6 +614,7 @@ + @@ -632,6 +648,7 @@ + @@ -720,9 +737,17 @@ + + + + + + + + @@ -742,8 +767,22 @@ + + + + + + + + + + + + + + @@ -753,6 +792,13 @@ + + + + + + + @@ -763,6 +809,7 @@ + @@ -794,11 +841,18 @@ + + + + + + + @@ -901,6 +955,8 @@ + + @@ -1289,6 +1345,7 @@ + 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 @@ + @@ -240,6 +241,7 @@ + @@ -298,6 +300,7 @@ + @@ -362,6 +365,7 @@ + @@ -431,6 +435,14 @@ + + + + + + + + @@ -526,6 +538,8 @@ + + @@ -553,6 +567,7 @@ + @@ -599,6 +614,7 @@ + @@ -632,6 +648,7 @@ + @@ -720,9 +737,17 @@ + + + + + + + + @@ -742,8 +767,22 @@ + + + + + + + + + + + + + + @@ -753,6 +792,13 @@ + + + + + + + @@ -763,6 +809,7 @@ + @@ -794,11 +841,18 @@ + + + + + + + @@ -901,6 +955,8 @@ + + @@ -1289,6 +1345,7 @@ + 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 @@ + + + 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 +% Copyright (C) 2007, 2008 Werner Lemberg % % 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 +% Copyright (C) 2008 Werner Lemberg % % 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 , +% +% 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-- +

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).

+ +

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.

+ +

Examples of usage can be found in the font related code.

+--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-- +

Most of the code that had accumulated here is now separated in +modules.

+--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-- +

We start with a registration system for atributes so that we can use the +symbolic names later on.

+--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-- +

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 .

+--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-- +

Access to nodes is what gives its power. Here we +implement a few helper functions. These functions are rather optimized.

+--ldx]]-- + +--[[ldx-- +

When manipulating node lists in , 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 was feasible from the perspective of performance.

+ +

First of all, we noticed that the bottleneck is more with excessive +callbacks (some gets called very often) and the conversion from and to +'s datastructures. However, at the end, we +found that inserting and deleting nodes in a table could become a +bottleneck.

+ +

This resulted in two special situations in passing nodes back to +: a table entry with value false is ignored, +and when instead of a table true is returned, the +original table is used.

+ +

Insertion is handled (at least in 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 inline 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 engine, but this is a not so natural extension.

+ +

When we collapse (something that we only do when really needed), we +also ignore the empty nodes. [This is obsolete!]

+--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-- +

The next function is not that much needed but in we use +for debugging node management.

+--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-- +

Not much is happening here.

+--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-- +

Here we only implement a few helper functions.

+--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-- +

The next function encapsulates the standard loader as +supplied by .

+--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-- +

We need to normalize the scale factor (in scaled points). This has to +do with the fact that uses a negative multiple of 1000 as +a signal for a font scaled based on the design size.

+--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-- +

Before a font is passed to we scale it. Here we also need +to scale virtual characters.

+--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-- +

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.)

+--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-- +

The reason why the scaler is split, is that for a while we experimented +with a helper function. However, in practice the calls are too slow to +make this profitable and the based variant was just faster. A days +wasted day but an experience richer.

+--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-- +

Analyzers run per script and/or language and are needed in order to +process features right.

+--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-- +

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.

+ + +we loop over all lookups +for each lookup we do a run over the list of glyphs +but we only process them for features that are enabled +if we're dealing with a contextual lookup, we loop over all contexts +in that loop we quit at a match and then process the list of sublookups +we always continue after the match + + +

In we do this for each font that is used in a list, so in +practice we have quite some nested loops.

+ +

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).

+ +

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.

+--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-- +

We start with a lot of tables and related functions.

+--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-- +

Here we go.

+--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-- +

This module is a bit more split up that I'd like but since we also want to test +with plain it has to be so. This module is part of +and discussion about improvements and functionality mostly happens on the + mailing list.

+ +

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.

+ +

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.

+ +

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 users ask for it.

+ +

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.

+ +

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 + 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 has to include +then in the output eventually.

+ +

The raw table as it coms from gets reorganized in to fit out needs. +In 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).

+ +

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.

+ +

As with the code, we may decide to store more information in the + table.

+ +

Incrementing the version number will force a re-cache. We jump the number by one +when there's a fix in the library or code that +results in different tables.

+--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 "" + 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-- +

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.

+--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-- +

I will implement multiple chain replacements once I run into a font that uses +it. It's not that complex to handle.

+--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-- +

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:

+ + +xxxabcdexxx [single a->A][multiple b->BCD][ligature cde->E] xxxABCDExxx + + +

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.

+--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-- +

Here we replace start by a single variant, First we delete the rest of the +match.

+--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-- +

Here we replace start by a sequence of new glyphs. First we delete the rest of +the match.

+--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-- +

Here we replace start by new glyph. First we delete the rest of the match.

+--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-- +

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).

+--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-- +

Here we deal with defining fonts. We do so by intercepting the +default loader that only handles .

+--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-- +

We hardly gain anything when we cache the final (pre scaled) + table. But it can be handy for debugging.

+--ldx]]-- + +fonts.version = 1.05 +fonts.cache = containers.define("fonts", "def", fonts.version, false) + +--[[ldx-- +

We can prefix a font specification by name: or +file:. The first case will result in a lookup in the +synonym table.

+ + +[ name: | file: ] identifier [ separator [ specification ] ] + + +

The following function split the font specification into components +and prepares a table that will move along as we proceed.

+--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-- +

A unique hash value is generated by:

+--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-- +

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 .

+--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-- +

We can resolve the filename using the next function:

+--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-- +

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.

+ +

We need to cache when possible. We do cache raw tfm data (from , or ). After that we can cache based +on specificstion (name) and size, that is, only needs a number +for an already loaded fonts. However, it may make sense to cache fonts +before they're scaled as well (store '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.

+ +

Watch out, here we do load a font, but we don't prepare the +specification yet.

+--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-- +

For virtual fonts we need a slightly different approach:

+--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-- +

Next follow the readers. This code was written while +evolved. Each one has its own way of dealing with its format.

+--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-- +

We need to check for default features. For this we provide +a helper function.

+--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-- +

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).

+ +In the previously defined reader (the one resulting in a +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.

+--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-- +

We overload both the and readers.

+--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-- +

Choosing a font by name and specififying its size is only part of the +game. In order to prevent complex commands, 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.

+ +

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.

+ +

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.

+--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(" ",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(" ", 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-- +

This module is a stripped down version of libraries that are used +by . 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 supp-mpl.tex.

+--ldx]]-- + +if metapost and metapost.version then + + --[[ldx-- +

Let's silently quit and make sure that no one loads it + manually in .

+ --ldx]]-- + +else + + local format, concat, abs = string.format, table.concat, math.abs + + local mplib = require ('mplib') + local kpse = require ('kpse') + + --[[ldx-- +

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.

+ +

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 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 + metapost.make(name,mem_name) that does the job.

+ --ldx]]-- + + metapost = metapost or { } + metapost.version = 1.00 + metapost.showlog = metapost.showlog or false + metapost.lastlog = "" + + --[[ldx-- +

A few helpers, taken from l-file.lua.

+ --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-- +

We use the library unless a finder is already + defined.

+ --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-- +

You can use your own reported if needed, as long as it handles multiple + arguments and formatted strings.

+ --ldx]]-- + + metapost.report = metapost.report or function(...) + texio.write(format("",format(...))) + end + + --[[ldx-- +

The rest of this module is not documented. More info can be found in the + manual, articles in user group journals and the files that + ship with .

+ --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-- +

We removed some message and tracing code. We might even remove the flusher

+ --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-- +

Support for specials has been removed.

+ --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 Taco Hoekwater - 566841 + 575117 - + 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 - + doc/context/bib/bibmod-doc.pdf doc/context/bib/bibmod-doc.tex 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 -- cgit v1.2.3