summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarius <mariausol@gmail.com>2010-08-14 15:54:19 +0300
committerMarius <mariausol@gmail.com>2010-08-14 15:54:19 +0300
commit39e30629c15ae4a899532d84c4abea127f2847a6 (patch)
treece9007341b23338cc6d73dad028f307c78dcb0ed
parent83a331fff83ac18314885a39e959ca0c10f316f7 (diff)
downloadcontext-39e30629c15ae4a899532d84c4abea127f2847a6.tar.gz
stable 2010.07.30 11:35
-rw-r--r--context/data/textadept/context.lua710
-rw-r--r--metapost/context/base/mp-core.mp531
-rw-r--r--metapost/context/base/mp-mlib.mp72
-rw-r--r--metapost/context/base/mp-page.mp4
-rw-r--r--scripts/context/lua/luatools.lua8185
-rw-r--r--scripts/context/lua/luatools.rme3
-rw-r--r--scripts/context/lua/mtx-context.lua2
-rw-r--r--scripts/context/lua/mtx-update.lua5
-rw-r--r--scripts/context/lua/mtxrun.rme18
-rw-r--r--scripts/context/stubs/mswin/luatools.lua8185
-rw-r--r--scripts/context/stubs/mswin/mptopdf.exebin0 -> 6144 bytes
-rw-r--r--scripts/context/stubs/unix/mptopdf2
-rw-r--r--tex/context/base/back-ini.lua13
-rw-r--r--tex/context/base/back-pdf.lua60
-rw-r--r--tex/context/base/back-pdf.mkiv2
-rw-r--r--tex/context/base/bibl-bib.mkiv2
-rw-r--r--tex/context/base/buff-ini.mkiv9
-rw-r--r--tex/context/base/buff-ver.mkiv12
-rw-r--r--tex/context/base/cont-new.tex2
-rw-r--r--tex/context/base/context.mkiv2
-rw-r--r--tex/context/base/context.tex2
-rw-r--r--tex/context/base/core-mis.mkiv75
-rw-r--r--tex/context/base/core-sys.mkiv4
-rw-r--r--tex/context/base/core-uti.lua2
-rw-r--r--tex/context/base/core-uti.mkiv7
-rw-r--r--tex/context/base/data-kps.lua101
-rw-r--r--tex/context/base/font-ctx.lua7
-rw-r--r--tex/context/base/font-def.lua9
-rw-r--r--tex/context/base/font-gds.lua1
-rw-r--r--tex/context/base/font-ini.lua2
-rw-r--r--tex/context/base/font-ini.mkiv100
-rw-r--r--tex/context/base/font-otb.lua4
-rw-r--r--tex/context/base/font-oth.lua45
-rw-r--r--tex/context/base/font-pat.lua26
-rw-r--r--tex/context/base/grph-epd.lua23
-rw-r--r--tex/context/base/grph-epd.mkiv58
-rw-r--r--tex/context/base/grph-fig.mkiv4
-rw-r--r--tex/context/base/grph-inc.lua82
-rw-r--r--tex/context/base/grph-inc.mkiv3
-rw-r--r--tex/context/base/lang-ini.mkiv13
-rw-r--r--tex/context/base/lang-lab.mkiv48
-rw-r--r--tex/context/base/lang-mis.mkiv2
-rw-r--r--tex/context/base/lang-sla.tex2
-rw-r--r--tex/context/base/lpdf-ano.lua60
-rw-r--r--tex/context/base/lpdf-epa.lua162
-rw-r--r--tex/context/base/lpdf-epd.lua246
-rw-r--r--tex/context/base/lpdf-fld.lua29
-rw-r--r--tex/context/base/lpdf-ini.lua114
-rw-r--r--tex/context/base/lpdf-ini.mkiv1
-rw-r--r--tex/context/base/lpdf-mis.lua45
-rw-r--r--tex/context/base/lpdf-pdx.lua75
-rw-r--r--tex/context/base/lpdf-ren.lua4
-rw-r--r--tex/context/base/lpdf-swf.lua23
-rw-r--r--tex/context/base/lpdf-tag.lua390
-rw-r--r--tex/context/base/lpdf-u3d.lua31
-rw-r--r--tex/context/base/lpdf-wid.lua48
-rw-r--r--tex/context/base/lpdf-xmp.lua16
-rw-r--r--tex/context/base/luat-cnf.lua2
-rw-r--r--tex/context/base/luat-cod.lua12
-rw-r--r--tex/context/base/luat-cod.mkiv2
-rw-r--r--tex/context/base/luat-ini.mkiv19
-rw-r--r--tex/context/base/luat-run.lua10
-rw-r--r--tex/context/base/luat-sto.lua4
-rw-r--r--tex/context/base/math-ini.mkiv12
-rw-r--r--tex/context/base/math-noa.lua98
-rw-r--r--tex/context/base/math-tag.lua247
-rw-r--r--tex/context/base/mlib-pdf.mkiv6
-rw-r--r--tex/context/base/mlib-run.lua280
-rw-r--r--tex/context/base/mult-de.tex3
-rw-r--r--tex/context/base/mult-def.lua18
-rw-r--r--tex/context/base/mult-en.tex3
-rw-r--r--tex/context/base/mult-fr.tex3
-rw-r--r--tex/context/base/mult-it.tex3
-rw-r--r--tex/context/base/mult-nl.tex3
-rw-r--r--tex/context/base/mult-ro.tex3
-rw-r--r--tex/context/base/mult-sys.tex3
-rw-r--r--tex/context/base/node-acc.lua102
-rw-r--r--tex/context/base/node-aux.lua47
-rw-r--r--tex/context/base/node-ini.mkiv1
-rw-r--r--tex/context/base/node-ref.lua14
-rw-r--r--tex/context/base/node-res.lua2
-rw-r--r--tex/context/base/node-rul.lua95
-rw-r--r--tex/context/base/node-rul.mkiv8
-rw-r--r--tex/context/base/node-tra.lua2
-rw-r--r--tex/context/base/pack-rul.mkiv4
-rw-r--r--tex/context/base/page-ini.mkiv7
-rw-r--r--tex/context/base/page-mul.mkiv23
-rw-r--r--tex/context/base/s-pre-69.tex314
-rw-r--r--tex/context/base/strc-bkm.lua4
-rw-r--r--tex/context/base/strc-des.mkiv18
-rw-r--r--tex/context/base/strc-flt.mkiv26
-rw-r--r--tex/context/base/strc-itm.mkiv22
-rw-r--r--tex/context/base/strc-lst.lua20
-rw-r--r--tex/context/base/strc-lst.mkiv38
-rw-r--r--tex/context/base/strc-mat.mkiv12
-rw-r--r--tex/context/base/strc-not.lua27
-rw-r--r--tex/context/base/strc-not.mkiv21
-rw-r--r--tex/context/base/strc-ref.lua2
-rw-r--r--tex/context/base/strc-ref.mkiv28
-rw-r--r--tex/context/base/strc-reg.mkiv55
-rw-r--r--tex/context/base/strc-sbe.mkiv2
-rw-r--r--tex/context/base/strc-sec.mkiv21
-rw-r--r--tex/context/base/strc-tag.lua85
-rw-r--r--tex/context/base/strc-tag.mkiv192
-rw-r--r--tex/context/base/tabl-ntb.mkiv25
-rw-r--r--tex/context/base/tabl-tbl.mkiv7
-rw-r--r--tex/context/base/task-ini.lua8
-rw-r--r--tex/context/base/trac-deb.lua20
-rw-r--r--tex/context/base/trac-lmx.mkiv16
-rw-r--r--tex/context/base/type-ini.mkiv4
-rw-r--r--tex/context/base/type-otf.mkiv7
-rw-r--r--tex/context/base/x-mathml.mkiv6
-rw-r--r--tex/context/fonts/xits-math.lfg12
-rw-r--r--tex/context/interface/keys-cs.xml3
-rw-r--r--tex/context/interface/keys-de.xml3
-rw-r--r--tex/context/interface/keys-en.xml3
-rw-r--r--tex/context/interface/keys-fr.xml3
-rw-r--r--tex/context/interface/keys-it.xml3
-rw-r--r--tex/context/interface/keys-nl.xml3
-rw-r--r--tex/context/interface/keys-pe.xml3
-rw-r--r--tex/context/interface/keys-ro.xml3
-rw-r--r--tex/generic/context/luatex-fonts-merged.lua17
122 files changed, 3565 insertions, 18187 deletions
diff --git a/context/data/textadept/context.lua b/context/data/textadept/context.lua
deleted file mode 100644
index f386eb87d..000000000
--- a/context/data/textadept/context.lua
+++ /dev/null
@@ -1,710 +0,0 @@
---[[
- Preliminary ConTeXT lexer
-
- % ConTeXt
- tex context
- mkii context
- mkiv context
-
- experiment dd 2009/10/28 .. todo:
-
- -- figure out if tabs instead of splits are possible
- -- locate an option to enter name in file dialogue (like windows permits)
- -- nesting of lua somehow does not re-lex while typing (backtrack till begin_...)
- -- find trick to overload latex lexer (mime_types, metatype trickery)
- -- convert scite lua scripts to textadept
- -- check linux and osx versions
- -- figure out why loading a file fails (lfs too)
-
- so, this is just an experiment
-
-]]--
-
-local textadept = _G.textadept
-
-module(..., package.seeall)
-
-local context = context
-local lua = require 'lua'
-
-local P, R, S, V = lpeg.P, lpeg.R, lpeg.S, lpeg.V
-
---~ local some_words = { "starttext", "stoptext", "writestatus" }
-
-local some_words = {
- "CAP",
- "Cap",
- "Caps",
- "Character",
- "Characters",
- "MONTH",
- "Romannumerals",
- "WEEKDAY",
- "WORD",
- "WORDS",
- "Word",
- "Words",
- "about",
- "adaptlayout",
- "adding",
- "appendix",
- "arg",
- "at",
- "atpage",
- "background",
- "blackrule",
- "blackrules",
- "blank",
- "bookmark",
- "but",
- "button",
- "bypassblocks",
- "cap",
- "chapter",
- "character",
- "characters",
- "chem",
- "clip",
- "clonefield",
- "color",
- "column",
- "comment",
- "comparecolorgroup",
- "comparepalet",
- "completecombinedlist",
- "completelistoffloats",
- "completelistofsorts",
- "completelistofsynonyms",
- "completeregister",
- "convertnumber",
- "copyfield",
- "correctwhitespace",
- "coupledocument",
- "coupledregister",
- "couplemarking",
- "couplepage",
- "couplepaper",
- "coupleregister",
- "crlf",
- "currentdate",
- "currentheadnumber",
- "date",
- "decouplemarking",
- "define",
- "defineblank",
- "defineblock",
- "definebodyfont",
- "definebodyfontenvironment",
- "definebuffer",
- "definecolor",
- "definecolorgroup",
- "definecombinedlist",
- "defineconversion",
- "definedescription",
- "defineenumeration",
- "definefield",
- "definefieldstack",
- "definefiguresymbol",
- "definefloat",
- "definefont",
- "defineframed",
- "defineframedtext",
- "definehead",
- "defineindenting",
- "defineinteractionmenu",
- "defineinteractionmenu",
- "definelabel",
- "definelist",
- "definelogo",
- "definemakeup",
- "definemarking",
- "defineoutput",
- "defineoverlay",
- "definepalet",
- "definepapersize",
- "defineparagraphs",
- "defineprofile",
- "defineprogram",
- "definerawfont",
- "definereference",
- "definereferenceformat",
- "definereferencelist",
- "defineregister",
- "definerule",
- "definesection",
- "definesectionblock",
- "definesorting",
- "definestartstop",
- "definesubfield",
- "definesymbol",
- "definesynonyms",
- "definetabletemplate",
- "definetabulate",
- "definetext",
- "definetextposition",
- "definetextvariable",
- "definetype",
- "definetyping",
- "defineversion",
- "description",
- "determineheadnumber",
- "determinelistcharacteristics",
- "disableinteractionmenu",
- "donttest",
- "emptylines",
- "enumeration",
- "externalfigure",
- "field",
- "fieldstack",
- "fillinfield",
- "fillinline",
- "fillinrules",
- "fillintext",
- "fitfield",
- "fixedspaces",
- "followprofile",
- "followprofileversion",
- "followversion",
- "footnote",
- "footnotetext",
- "forceblocks",
- "fraction",
- "framed",
- "framedtext",
- "from",
- "getbuffer",
- "getmarking",
- "godown",
- "goto",
- "gotobox",
- "graycolor",
- "grid",
- "hairline",
- "head",
- "headnumber",
- "headtext",
- "hideblocks",
- "high",
- "hl",
- "in",
- "indentation",
- "indenting",
- "inframed",
- "ininner",
- "inleft",
- "inline",
- "inmargin",
- "inothermargin",
- "inouter",
- "inright",
- "installlanguage",
- "interactionbar",
- "interactionbuttons",
- "item",
- "items",
- "its",
- "keepblocks",
- "labeling",
- "labels",
- "labeltext",
- "language",
- "leftaligned",
- "listsymbol",
- "loadsorts",
- "loadsynonyms",
- "logfields",
- "lohi",
- "low",
- "mainlanguage",
- "mar",
- "marginrule",
- "margintext",
- "marking",
- "markversion",
- "mathematics",
- "mediaeval",
- "midaligned",
- "mirror",
- "month",
- "moveongrid",
- "name",
- "nextsection",
- "nocap",
- "noheaderandfooterlines",
- "noindenting",
- "nolist",
- "nomarking",
- "nomoreblocks",
- "nomorefiles",
- "nop",
- "nospace",
- "note",
- "notopandbottomlines",
- "nowhitespace",
- "numbers",
- "overbar",
- "overbars",
- "overstrike",
- "overstrikes",
- "packed",
- "page",
- "pagereference",
- "pagetype",
- "paragraph",
- "part",
- "periods",
- "placebookmarks",
- "placecombinedlist",
- "placecombinedlist",
- "placefloat",
- "placefootnotes",
- "placeformula",
- "placelegend",
- "placelist",
- "placelistoffloats",
- "placelistofsorts",
- "placelistofsynonyms",
- "placelocalfootnotes",
- "placelogos",
- "placeongrid",
- "placeontopofeachother",
- "placereferencelist",
- "placeregister",
- "placeregister",
- "placerule",
- "placesidebyside",
- "placesubformula",
- "placetextvariable",
- "position",
- "positiontext",
- "processblocks",
- "processpage",
- "program",
- "publication",
- "quotation",
- "quote",
- "ran",
- "ref",
- "reference",
- "referral",
- "referraldate",
- "register",
- "reservefloat",
- "reset",
- "resetmarking",
- "resettextcontent",
- "rightaligned",
- "romannumerals",
- "rotate",
- "scale",
- "screen",
- "section",
- "seeregister",
- "selectblocks",
- "selectpaper",
- "selectversion",
- "settextcontent",
- "settextvariable",
- "setupalign",
- "setuparranging",
- "setupbackground",
- "setupbackgrounds",
- "setupblackrules",
- "setupblank",
- "setupblock",
- "setupbodyfont",
- "setupbodyfontenvironment",
- "setupbottom",
- "setupbottomtexts",
- "setupbuffer",
- "setupbuttons",
- "setupcapitals",
- "setupcaption",
- "setupcaptions",
- "setupclipping",
- "setupcolor",
- "setupcolors",
- "setupcolumns",
- "setupcombinations",
- "setupcombinedlist",
- "setupcomment",
- "setupdescriptions",
- "setupenumerations",
- "setupexternalfigures",
- "setupfield",
- "setupfields",
- "setupfillinlines",
- "setupfillinrules",
- "setupfloat",
- "setupfloats",
- "setupfloatsplitting",
- "setupfooter",
- "setupfootertexts",
- "setupfootnotedefinition",
- "setupfootnotes",
- "setupforms",
- "setupformulae",
- "setupframed",
- "setupframedtexts",
- "setuphead",
- "setupheader",
- "setupheadertexts",
- "setupheadnumber",
- "setupheads",
- "setupheadtext",
- "setuphyphenmark",
- "setupindentations",
- "setupindenting",
- "setupinmargin",
- "setupinteraction",
- "setupinteractionbar",
- "setupinteractionscreen",
- "setupinterlinespace",
- "setupinterlinespace",
- "setupitemgroup",
- "setupitems",
- "setuplabeltext",
- "setuplanguage",
- "setuplayout",
- "setuplegend",
- "setuplinenumbering",
- "setuplines",
- "setuplinewidth",
- "setuplist",
- "setuplistalternative",
- "setupmakeup",
- "setupmarginblocks",
- "setupmarginrules",
- "setupmarking",
- "setupnarrower",
- "setupnumbering",
- "setupoppositeplacing",
- "setupoutput",
- "setuppagenumber",
- "setuppagenumbering",
- "setuppagetransitions",
- "setuppalet",
- "setuppaper",
- "setuppapersize",
- "setupparagraphnumbering",
- "setupparagraphs",
- "setuppositioning",
- "setupprofiles",
- "setupprograms",
- "setuppublications",
- "setupquote",
- "setupreferencelist",
- "setupreferencing",
- "setupregister",
- "setuprotate",
- "setuprule",
- "setupscreens",
- "setupsection",
- "setupsectionblock",
- "setupsorting",
- "setupspacing",
- "setupstrut",
- "setupsubpagenumber",
- "setupsymbolset",
- "setupsynchronization",
- "setupsynchronizationbar",
- "setupsynonyms",
- "setupsystem",
- "setuptab",
- "setuptables",
- "setuptabulate",
- "setuptext",
- "setuptextposition",
- "setuptextrules",
- "setuptexttexts",
- "setuptextvariable",
- "setupthinrules",
- "setuptolerance",
- "setuptop",
- "setuptoptexts",
- "setuptype",
- "setuptyping",
- "setupunderbar",
- "setupurl",
- "setupversions",
- "setupwhitespace",
- "showbodyfont",
- "showbodyfontenvironment",
- "showcolor",
- "showcolorgroup",
- "showexternalfigures",
- "showfields",
- "showframe",
- "showgrid",
- "showlayout",
- "showmakeup",
- "showpalet",
- "showprint",
- "showsetups",
- "showstruts",
- "showsymbolset",
- "someline",
- "somewhere",
- "sort",
- "space",
- "splitfloat",
- "startalignment",
- "startbackground",
- "startbuffer",
- "startcolor",
- "startcolumns",
- "startcombination",
- "startcomment",
- "startcomponent",
- "startdescription",
- "startdocument",
- "startenumeration",
- "startenvironment",
- "startfact",
- "startfigure",
- "startfloattext",
- "startformula",
- "startframedtext",
- "starthiding",
- "startinteractionmenu",
- "startitemgroup",
- "startlegend",
- "startline",
- "startlinecorrection",
- "startlinenumbering",
- "startlines",
- "startlocal",
- "startlocalenvironment",
- "startlocalfootnotes",
- "startmakeup",
- "startmarginblock",
- "startmarginrule",
- "startnamemakeup",
- "startnarrower",
- "startopposite",
- "startoverlay",
- "startoverview",
- "startpacked",
- "startparagraph",
- "startpositioning",
- "startpostponing",
- "startproduct",
- "startprofile",
- "startproject",
- "startquotation",
- "startregister",
- "startsymbolset",
- "startsynchronization",
- "starttable",
- "starttables",
- "starttabulate",
- "starttextrule",
- "starttyping",
- "startunpacked",
- "startversion",
- "stopalignment",
- "stopbackground",
- "stopbuffer",
- "stopcolor",
- "stopcolumns",
- "stopcombination",
- "stopcomment",
- "stopcomponent",
- "stopdescription",
- "stopdocument",
- "stopenumeration",
- "stopenvironment",
- "stopfact",
- "stopfigure",
- "stopfloattext",
- "stopformula",
- "stopframedtext",
- "stophiding",
- "stopinteractionmenu",
- "stopitemgroup",
- "stoplegend",
- "stopline",
- "stoplinecorrection",
- "stoplinenumbering",
- "stoplines",
- "stoplocal",
- "stoplocalenvironment",
- "stoplocalfootnotes",
- "stopmakeup",
- "stopmarginblock",
- "stopmarginrule",
- "stopnamemakeup",
- "stopnarrower",
- "stopopposite",
- "stopoverlay",
- "stopoverview",
- "stoppacked",
- "stopparagraph",
- "stoppositioning",
- "stoppostponing",
- "stopproduct",
- "stopprofile",
- "stopproject",
- "stopquotation",
- "stopsymbolset",
- "stopsynchronization",
- "stoptable",
- "stoptables",
- "stoptabulate",
- "stoptextrule",
- "stoptyping",
- "stopunpacked",
- "stopversion",
- "stretched",
- "sub",
- "subject",
- "subsection",
- "subsubject",
- "subsubsection",
- "subsubsubject",
- "switchtobodyfont",
- "switchtorawfont",
- "sym",
- "symbol",
- "synchronizationbar",
- "synchronize",
- "synonym",
- "tab",
- "tex",
- "textreference",
- "textrule",
- "textvariable",
- "thinrule",
- "thinrules",
- "title",
- "tooltip",
- "translate",
- "typ",
- "type",
- "typebuffer",
- "typefile",
- "underbar",
- "underbars",
- "useURL",
- "useblocks",
- "usecommands",
- "usedirectory",
- "useencoding",
- "useexternaldocument",
- "useexternalfigure",
- "useexternalfile",
- "useexternalfiles",
- "useexternalsoundtrack",
- "usemodule",
- "usereferences",
- "usespecials",
- "usesymbols",
- "version",
- "vl",
- "weekday",
- "whitespace",
- "wordright",
- "writebetweenlist",
- "writetolist",
- "writetoreferencelist",
- "writetoregister",
-}
-
-local tex_word_match = word_match(word_list(some_words))
-
---~ local function tex_preamble_match()
---~ return P(function(input, index)
---~ if index < 10 then
---~ local s, e, word = input:find('^(.+)[\n\r]',index)
---~ if word then
---~ local interface = word:match("interface=(..)")
---~ if interface then
---~ local name = "c:/data/develop/context/lua/textadept/cont-" .. interface .. "-scite.lua"
---~ --~ local f = io.open(name,"rb") -- fails
---~ if f then
---~ local data = f:read("*all")
---~ data = data and loadstring(data)
---~ data = data and data()
---~ if data and type(data) == "table" then
---~ some_words = word_list(data)
---~ context.LoadTokens()
---~ -- InitLexer(context)
---~ end
---~ f:close()
---~ end
---~ end
---~ end
---~ end
---~ return false
---~ end)
---~ end
-
-local spacing = token('whitespace', S(" \n\r\t\f")^1)
---~ local preamble = token('preamble', P('%') * tex_preamble_match())
-local comment = token('comment', P('%') * (1-S("\n\r"))^0)
-local keyword = token('keyword', P('\\') * tex_word_match)
-local command = token('command', P('\\') * ((R("az","AZ")+S("@!?"))^1 + P(1)))
-local grouping = token('grouping', S("{$}"))
-local specials = token('specials', S("#()[]<>=\""))
-local extras = token('extras', S("`~%^&_-+/\'|"))
-
--- LexByLine = true
-
-local startluacode = token("grouping", P("\\startluacode"))
-local stopluacode = token("grouping", P("\\stopluacode"))
---~ local startctxlua = token("grouping", P("\\ctxlua") * spacing^0 * P("{"))
---~ local stopctxlua = token("grouping", P("}"))
-
---~ local startMPcode = token("grouping", P("\\startMPcode"))
---~ local stopMPcode = token("grouping", P("\\stopMPcode"))
---~ local startuseMPgraphic = token("grouping", P("\\startuseMPgraphic"))
---~ local stopuseMPgraphic = token("grouping", P("\\stopuseMPgraphic"))
---~ local startreusableMPgraphic = token("grouping", P("\\startreusableMPgraphic"))
---~ local stopreusableMPgraphic = token("grouping", P("\\stopreusableMPgraphic"))
---~ local startuniqueMPgraphic = token("grouping", P("\\startuniqueMPgraphic"))
---~ local stopuniqueMPgraphic = token("grouping", P("\\stopuniqueMPgraphic"))
-
-function LoadTokens()
-
- lua.LoadTokens()
-
- add_token(context, 'whitespace', spacing)
---~ add_token(context, 'preamble', preamble)
- add_token(context, 'comment', comment)
- add_token(context, 'keyword', keyword)
- add_token(context, 'command', command)
- add_token(context, 'grouping', grouping)
- add_token(context, 'specials', specials)
- add_token(context, 'extras', extras)
- add_token(context, 'any_char', any_char)
-
- lua.TokenPatterns.any_char = token('default', 1 - stopluacode)
-
- make_embeddable(lua, context, startluacode, stopluacode)
--- make_embeddable(lua, context, startctxlua, stopctxlua) -- no multiple embeddables unless more complex anychar
- embed_language(context, lua)
-
--- metapost.LoadTokens()
--- metapost.TokenPatterns.any_char = token('any_char', 1 - stopMPcode - stopuseMPgraphic - stopreusableMPgraphic - stopuniqueMPgraphic)
--- make_embeddable(metapost, context, startMPcode, stopMPcode )
--- make_embeddable(metapost, context, startuseMPgraphic, stopuseMPgraphic )
--- make_embeddable(metapost, context, startreusableMPgraphic, stopreusableMPgraphic)
--- make_embeddable(metapost, context, startuniqueMPgraphic, stopuniqueMPgraphic )
-end
-
-local bold = true
-local italic = true
-
-function LoadStyles()
- add_style('preamble', style_nothing .. { fore = colors.yellow, bold = bold })
- add_style('comment', style_nothing .. { fore = colors.yellow, bold = bold })
- add_style('keyword', style_nothing .. { fore = colors.green, bold = bold, italic = italic })
- add_style('command', style_nothing .. { fore = colors.green, bold = bold })
- add_style('grouping', style_nothing .. { fore = colors.red, bold = bold })
- add_style('specials', style_nothing .. { fore = colors.blue, bold = bold })
- add_style('extras', style_nothing .. { fore = colors.yellow, bold = bold })
-end
-
---~ textadept.mime_types.extensions["tex"] = context
---~ textadept.mime_types.extensions["mkii"] = context
---~ textadept.mime_types.extensions["mkiv"] = context
diff --git a/metapost/context/base/mp-core.mp b/metapost/context/base/mp-core.mp
index 7c5d5a1c1..2ccdad22c 100644
--- a/metapost/context/base/mp-core.mp
+++ b/metapost/context/base/mp-core.mp
@@ -402,19 +402,22 @@ def prepare_multi_pars (expr fn,fx,fy,fw,fh,fd,
set_par_line_height (ph, pd) ;
- numeric par_hang_indent, par_hang_after, par_indent, par_left_skip ;
+ numeric par_hang_indent, par_hang_after, par_indent, par_left_skip, par_right_skip ;
par_hang_indent := rh ;
par_hang_after := ra ;
par_indent := ri ;
par_left_skip := rl ;
+ par_right_skip := rr ;
pair par_start_pos ;
-
+ pair par_stop_pos ;
par_start_pos := llxy[fpos]
if par_indent <0: shifted (-par_indent, 0) fi
if par_left_skip<0: shifted (-par_left_skip,0) fi ;
+ par_stop_pos := lrxy[tpos]
+ if par_right_skip<0: shifted (par_right_skip,0) fi ; % nasty as the endpos can be shifted by rightskip
if wxy[wpos]>0 :
left_skip := rl + xpart llxy[wpos] - xpart llxy[ppos] ;
@@ -430,249 +433,247 @@ def prepare_multi_pars (expr fn,fx,fy,fw,fh,fd,
numeric multi_par_pages ; multi_par_pages := nxy[tpos]-nxy[fpos]+1 ;
- vardef snapped_multi_pos (expr p) =
- if snap_multi_par_tops :
- if abs(ypart p - ypart ulcorner multipar) < par_line_height :
- (xpart p,ypart ulcorner multipar)
- else :
- p
- fi
+ % locals .. why can't i move these outside?
+
+vardef _pmp_set_multipar_ (expr i) =
+ ( (TextAreas[i] leftenlarged -left_skip) rightenlarged (-right_skip
+ if auto_multi_par_hsize : + rw - bbwidth(TextAreas[i]) fi) )
+enddef ;
+
+vardef _pmp_snapped_multi_pos_ (expr p) =
+ if snap_multi_par_tops :
+ if abs(ypart p - ypart ulcorner multipar) < par_line_height :
+ (xpart p,ypart ulcorner multipar)
else :
p
fi
- enddef ;
+ else :
+ p
+ fi
+enddef ;
- % def set_multipar (expr i) =
- % ((TextAreas[i] leftenlarged -left_skip) rightenlarged -right_skip)
- % enddef ;
+vardef _pmp_estimated_par_lines_ (expr h) =
+ round(h/par_line_height)
+enddef ;
- vardef set_multipar (expr i) =
- ( (TextAreas[i] leftenlarged -left_skip) rightenlarged (-right_skip
- if auto_multi_par_hsize : + rw - bbwidth(TextAreas[i]) fi) )
- enddef ;
+vardef _pmp_top_multi_par_(expr p) =
+ (round(_pmp_estimated_par_lines_(bbheight(p)*par_line_height))=round(bbheight(p)))
+enddef ;
- vardef top_multi_par(expr p) =
- (round(estimated_par_lines(bbheight(p)*par_line_height))=round(bbheight(p)))
- enddef ;
+vardef _pmp_multi_par_tsc_(expr p) =
+ if _pmp_top_multi_par_(p) : TopSkipCorrection else : 0 fi
+enddef ;
- vardef multi_par_tsc(expr p) =
- if top_multi_par(p) : TopSkipCorrection else : 0 fi
- enddef ;
+vardef _pmp_estimated_multi_par_height_ (expr n, t) =
+ if round(par_line_height)=0 :
+ 0
+ else :
+ save ok, h ; boolean ok ;
+ numeric h ; h := 0 ;
+ ok := false ;
+ if (nxy[fpos]=RealPageNumber-1) :
+ for i := 1 upto NOfSavedTextAreas :
+ if (InsideSavedTextArea(i,par_start_pos)) :
+ ok := true ;
+ h := h + _pmp_estimated_par_lines_(ypart ulxy[fpos] -
+ ypart llcorner SavedTextAreas[i]) ;
+ elseif ok :
+ h := h + _pmp_estimated_par_lines_(bbheight(SavedTextAreas[i])) ;
+ fi ;
+ endfor ;
+ fi ;
+ if ok :
+ for i := 1 upto n-1 :
+ h := h + _pmp_estimated_par_lines_(bbheight(TextAreas[i])) ;
+ endfor ;
+ else :
+ % already: ok := false ;
+ for i := 1 upto n-1 :
+ if (InsideTextArea(i,par_start_pos)) :
+ ok := true ;
+ h := h + _pmp_estimated_par_lines_(ypart ulxy[fpos] - ypart llcorner TextAreas[i]) ;
+ elseif ok :
+ h := h + _pmp_estimated_par_lines_(bbheight(TextAreas[i])) ;
+ fi ;
+ endfor ;
+ fi ;
+ h
+ fi
+enddef ;
- vardef estimated_par_lines (expr h) =
- round(h/par_line_height)
- enddef ;
+vardef _pmp_left_top_hang_ (expr same_area) =
- vardef estimated_multi_par_height (expr n, t) =
- if round(par_line_height)=0 :
- 0
- else :
- save ok, h ; boolean ok ;
- numeric h ; h := 0 ;
- ok := false ;
- if (nxy[fpos]=RealPageNumber-1) :
- for i := 1 upto NOfSavedTextAreas :
- if (InsideSavedTextArea(i,par_start_pos)) :
- ok := true ;
- h := h + estimated_par_lines(ypart ulxy[fpos] -
- ypart llcorner SavedTextAreas[i]) ;
- elseif ok :
- h := h + estimated_par_lines(bbheight(SavedTextAreas[i])) ;
- fi ;
- endfor ;
- fi ;
- if ok :
- for i := 1 upto n-1 :
- h := h + estimated_par_lines(bbheight(TextAreas[i])) ;
- endfor ;
- else :
- % already: ok := false ;
- for i := 1 upto n-1 :
- if (InsideTextArea(i,par_start_pos)) :
- ok := true ;
- h := h + estimated_par_lines(ypart ulxy[fpos] - ypart llcorner TextAreas[i]) ;
- elseif ok :
- h := h + estimated_par_lines(bbheight(TextAreas[i])) ;
- fi ;
- endfor ;
- fi ;
- h
- fi
- enddef ;
+ par_hang_after := ra + _pmp_estimated_par_lines_(py-fy) ;
- vardef left_top_hang (expr same_area) =
+ if (par_hang_indent>0) and (par_hang_after<0) and obey_multi_par_hang :
+ pair _ul_ ; _ul_ := (xpart ulcorner multipar, ypart _pmp_snapped_multi_pos_(ulxy[fpos]));
+ pair _pa_ ; _pa_ := _ul_ shifted (0,par_hang_after*par_line_height) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_ -TopSkipCorrection,ypart llcorner multipar)) ;
+ if same_area :
+ _pa_ := (xpart _pa_,max(ypart _pa_ -TopSkipCorrection,ypart llxy[tpos])) ;
+ fi ;
+ if obey_multi_par_more and (round(par_line_height)>0) :
+ par_hang_after := min(0,round(par_hang_after +
+ (ypart urxy[fpos]-ypart _pa_)/par_line_height)) ;
+ fi ;
+ (xpart _ul_ + par_hang_indent, ypart lrxy[fpos]) --
+ (xpart _ul_ + par_hang_indent, ypart _pa_) --
+ (xpart ulcorner multipar, ypart _pa_)
+ else :
+ (xpart ulcorner multipar, ypart lrxy[fpos])
+ fi
+enddef ;
- par_hang_after := ra + estimated_par_lines(py-fy) ;
+vardef _pmp_right_top_hang_ (expr same_area) =
- 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]));
- pair _pa_ ; _pa_ := _ul_ shifted (0,par_hang_after*par_line_height) ;
- _pa_ := (xpart _pa_,max(ypart _pa_ -TopSkipCorrection,ypart llcorner multipar)) ;
- if same_area :
- _pa_ := (xpart _pa_,max(ypart _pa_ -TopSkipCorrection,ypart llxy[tpos])) ;
- fi ;
- if obey_multi_par_more and (round(par_line_height)>0) :
- par_hang_after := min(0,round(par_hang_after +
- (ypart urxy[fpos]-ypart _pa_)/par_line_height)) ;
- fi ;
- (xpart _ul_ + par_hang_indent, ypart lrxy[fpos]) --
- (xpart _ul_ + par_hang_indent, ypart _pa_) --
- (xpart ulcorner multipar, ypart _pa_)
- else :
- (xpart ulcorner multipar, ypart lrxy[fpos])
- fi
- enddef ;
+ par_hang_after := ra + _pmp_estimated_par_lines_(py-fy) ;
- vardef right_top_hang (expr same_area) =
+ if (par_hang_indent<0) and (par_hang_after<0) and obey_multi_par_hang :
+ pair _ur_ ; _ur_ := (xpart urcorner multipar, ypart _pmp_snapped_multi_pos_(urxy[fpos])) ;
+ pair _pa_ ; _pa_ := _ur_ shifted (0,par_hang_after*par_line_height) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_ -TopSkipCorrection,ypart llcorner multipar)) ;
+ if same_area :
+ _pa_ := (xpart _pa_,max(ypart _pa_ -TopSkipCorrection,ypart _pmp_snapped_multi_pos_(ulxy[tpos]))) ;
+ fi ;
+ if obey_multi_par_more and (round(par_line_height)>0) :
+ par_hang_after := min(0,round(par_hang_after +
+ (ypart urxy[fpos]-ypart _pa_)/par_line_height)) ;
+ fi ;
+ (xpart urcorner multipar, ypart _pa_) --
+ (xpart _ur_ + par_hang_indent, ypart _pa_) --
+ (xpart _ur_ + par_hang_indent, ypart _pmp_snapped_multi_pos_(urxy[fpos]))
+ else :
+ (xpart urcorner multipar, ypart _pmp_snapped_multi_pos_(urxy[fpos]))
+ fi
+enddef ;
- par_hang_after := ra + estimated_par_lines(py-fy) ;
+vardef _pmp_x_left_top_hang_ (expr i, t) =
+ par_hang_after := min(0,ra + _pmp_estimated_multi_par_height_(i,t)) ;
+ if (par_hang_indent>0) and (par_hang_after<0) :
+ pair _ul_ ; _ul_ := ulcorner multipar ;
+ pair _pa_ ; _pa_ := _ul_ shifted (0,par_hang_after*par_line_height) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart llcorner multipar)) ;
+ if t :
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart llxy[tpos]));
+ fi ;
+ if abs(ypart _pa_-ypart llxy[tpos])<par_line_height :
+ _pa_ := (xpart _pa_,ypart llxy[tpos]);
+ fi ;
+ if abs(ypart _pa_-ypart llcorner multipar)<par_line_height :
+ _pa_ := (xpart _pa_,ypart llcorner multipar);
+ fi ;
+ (xpart _ul_, ypart _pa_) --
+ (xpart _ul_ + par_hang_indent, ypart _pa_) --
+ (xpart _ul_ + par_hang_indent, ypart _ul_)
+ else :
+ ulcorner multipar
+ fi
+enddef ;
- 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])) ;
- pair _pa_ ; _pa_ := _ur_ shifted (0,par_hang_after*par_line_height) ;
- _pa_ := (xpart _pa_,max(ypart _pa_ -TopSkipCorrection,ypart llcorner multipar)) ;
- if same_area :
- _pa_ := (xpart _pa_,max(ypart _pa_ -TopSkipCorrection,ypart snapped_multi_pos(ulxy[tpos]))) ;
- fi ;
- if obey_multi_par_more and (round(par_line_height)>0) :
- par_hang_after := min(0,round(par_hang_after +
- (ypart urxy[fpos]-ypart _pa_)/par_line_height)) ;
- fi ;
- (xpart urcorner multipar, ypart _pa_) --
- (xpart _ur_ + par_hang_indent, ypart _pa_) --
- (xpart _ur_ + par_hang_indent, ypart snapped_multi_pos(urxy[fpos]))
- else :
- (xpart urcorner multipar, ypart snapped_multi_pos(urxy[fpos]))
- fi
- enddef ;
-
- vardef x_left_top_hang (expr i, t) =
- par_hang_after := min(0,ra + estimated_multi_par_height(i,t)) ;
- if (par_hang_indent>0) and (par_hang_after<0) :
- pair _ul_ ; _ul_ := ulcorner multipar ;
- pair _pa_ ; _pa_ := _ul_ shifted (0,par_hang_after*par_line_height) ;
- _pa_ := (xpart _pa_,max(ypart _pa_,ypart llcorner multipar)) ;
- if t :
- _pa_ := (xpart _pa_,max(ypart _pa_,ypart llxy[tpos]));
- fi ;
- if abs(ypart _pa_-ypart llxy[tpos])<par_line_height :
- _pa_ := (xpart _pa_,ypart llxy[tpos]);
- fi ;
- if abs(ypart _pa_-ypart llcorner multipar)<par_line_height :
- _pa_ := (xpart _pa_,ypart llcorner multipar);
- fi ;
- (xpart _ul_, ypart _pa_) --
- (xpart _ul_ + par_hang_indent, ypart _pa_) --
- (xpart _ul_ + par_hang_indent, ypart _ul_)
- else :
- ulcorner multipar
- fi
- enddef ;
-
- vardef x_right_top_hang (expr i, t) =
- par_hang_after := min(0,ra + estimated_multi_par_height(i,t)) ;
- if (par_hang_indent<0) and (par_hang_after<0) :
- pair _ur_ ; _ur_ := urcorner multipar ;
- pair _pa_ ; _pa_ := _ur_ shifted (0,par_hang_after*par_line_height) ;
- _pa_ := (xpart _pa_,max(ypart _pa_,ypart lrcorner multipar)) ;
- if t :
- _pa_ := (xpart _pa_,max(ypart _pa_,ypart snapped_multi_pos(urxy[tpos]))) ;
- fi ;
- (xpart _ur_ + par_hang_indent, ypart _ur_) --
- (xpart _ur_ + par_hang_indent, ypart _pa_) --
- (xpart _ur_, ypart _pa_)
- else :
- urcorner multipar
- fi
- enddef ;
-
- vardef left_bottom_hang (expr same_area) =
- pair _ll_, _sa_, _pa_ ;
- _sa_ := if same_area : llxy[tpos] else : lrcorner multipar fi ;
- if (par_hang_indent>0) and (par_hang_after>0) and obey_multi_par_hang :
- _ll_ := (xpart ulcorner multipar, ypart snapped_multi_pos(ulxy[fpos])) ;
- _pa_ := _ll_ shifted (0,-par_hang_after*par_line_height) ;
- _pa_ := (xpart _pa_,max(ypart _pa_,ypart llcorner multipar)) ;
- if same_area :
- _pa_ := (xpart _pa_,max(ypart _pa_,ypart _sa_)) ;
- fi ;
- if obey_multi_par_more and (round(par_line_height)>0) :
- par_hang_after := max(0,round(par_hang_after -
- (ypart urxy[fpos]-ypart _pa_)/par_line_height)) ;
- fi ;
- _pa_ --
- (xpart _pa_ + par_hang_indent,ypart _pa_) --
- (xpart _pa_ + par_hang_indent,ypart _sa_)
- else :
- (xpart llcorner multipar, ypart _sa_)
- fi
- enddef ;
-
- vardef right_bottom_hang (expr same_area) =
- pair _lr_, _sa_, _pa_ ;
- _sa_ := if same_area : snapped_multi_pos(ulxy[tpos]) else : lrcorner multipar fi ;
- if (par_hang_indent<0) and (par_hang_after>0) and obey_multi_par_hang :
- _lr_ := (xpart urcorner multipar, ypart snapped_multi_pos(urxy[fpos])) ;
- _pa_ := _lr_ shifted (0,-par_hang_after*par_line_height) ;
- _pa_ := (xpart _pa_,max(ypart _pa_,ypart lrcorner multipar)) ;
- if same_area :
- _pa_ := (xpart _pa_,max(ypart _pa_,ypart snapped_multi_pos(ulxy[tpos]))) ;
- fi ;
- if obey_multi_par_more and (round(par_line_height)>0) :
- par_hang_after := max(0,round(par_hang_after -
- (ypart urxy[fpos]-ypart _pa_)/par_line_height)) ;
- fi ;
+vardef _pmp_x_right_top_hang_ (expr i, t) =
+ par_hang_after := min(0,ra + _pmp_estimated_multi_par_height_(i,t)) ;
+ if (par_hang_indent<0) and (par_hang_after<0) :
+ pair _ur_ ; _ur_ := urcorner multipar ;
+ pair _pa_ ; _pa_ := _ur_ shifted (0,par_hang_after*par_line_height) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart lrcorner multipar)) ;
+ if t :
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart _pmp_snapped_multi_pos_(urxy[tpos]))) ;
+ fi ;
+ (xpart _ur_ + par_hang_indent, ypart _ur_) --
+ (xpart _ur_ + par_hang_indent, ypart _pa_) --
+ (xpart _ur_, ypart _pa_)
+ else :
+ urcorner multipar
+ fi
+enddef ;
+
+vardef _pmp_left_bottom_hang_ (expr same_area) =
+ pair _ll_, _sa_, _pa_ ;
+ _sa_ := if same_area : llxy[tpos] else : lrcorner multipar fi ;
+ if (par_hang_indent>0) and (par_hang_after>0) and obey_multi_par_hang :
+ _ll_ := (xpart ulcorner multipar, ypart _pmp_snapped_multi_pos_(ulxy[fpos])) ;
+ _pa_ := _ll_ shifted (0,-par_hang_after*par_line_height) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart llcorner multipar)) ;
+ if same_area :
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart _sa_)) ;
+ fi ;
+ if obey_multi_par_more and (round(par_line_height)>0) :
+ par_hang_after := max(0,round(par_hang_after -
+ (ypart urxy[fpos]-ypart _pa_)/par_line_height)) ;
+ fi ;
+ _pa_ --
+ (xpart _pa_ + par_hang_indent,ypart _pa_) --
+ (xpart _pa_ + par_hang_indent,ypart _sa_)
+ else :
+ (xpart llcorner multipar, ypart _sa_)
+ fi
+enddef ;
+
+vardef _pmp_right_bottom_hang_ (expr same_area) =
+ pair _lr_, _sa_, _pa_ ;
+ _sa_ := if same_area : _pmp_snapped_multi_pos_(ulxy[tpos]) else : lrcorner multipar fi ;
+ if (par_hang_indent<0) and (par_hang_after>0) and obey_multi_par_hang :
+ _lr_ := (xpart urcorner multipar, ypart _pmp_snapped_multi_pos_(urxy[fpos])) ;
+ _pa_ := _lr_ shifted (0,-par_hang_after*par_line_height) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart lrcorner multipar)) ;
+ if same_area :
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart _pmp_snapped_multi_pos_(ulxy[tpos]))) ;
+ fi ;
+ if obey_multi_par_more and (round(par_line_height)>0) :
+ par_hang_after := max(0,round(par_hang_after -
+ (ypart urxy[fpos]-ypart _pa_)/par_line_height)) ;
+ fi ;
+ (xpart _pa_ + par_hang_indent,ypart _sa_) --
+ (xpart _pa_ + par_hang_indent,ypart _pa_) --
+ _pa_
+ else :
+ (xpart lrcorner multipar, ypart _sa_)
+ fi
+enddef ;
+
+vardef _pmp_x_left_bottom_hang_ (expr i, t) =
+ pair _ll_, _sa_, _pa_ ;
+ _sa_ := if t : llxy[tpos] else : llcorner multipar fi ;
+ if (par_hang_indent>0) and (ra>0) :
+ par_hang_after := max(0,ra - _pmp_estimated_multi_par_height_(i,t)) ;
+ _ll_ := ulcorner multipar ;
+ _pa_ := _ll_ shifted (0,-par_hang_after*par_line_height) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart llcorner multipar)) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart _sa_)) ;
+ % we need to compensate for topskip enlarged areas
+ if abs(ypart _pa_ - ypart _sa_) > par_line_height :
(xpart _pa_ + par_hang_indent,ypart _sa_) --
(xpart _pa_ + par_hang_indent,ypart _pa_) --
- _pa_
- else :
- (xpart lrcorner multipar, ypart _sa_)
fi
- enddef ;
-
- vardef x_left_bottom_hang (expr i, t) =
- pair _ll_, _sa_, _pa_ ;
- _sa_ := if t : llxy[tpos] else : llcorner multipar fi ;
- if (par_hang_indent>0) and (ra>0) :
- par_hang_after := max(0,ra - estimated_multi_par_height(i,t)) ;
- _ll_ := ulcorner multipar ;
- _pa_ := _ll_ shifted (0,-par_hang_after*par_line_height) ;
- _pa_ := (xpart _pa_,max(ypart _pa_,ypart llcorner multipar)) ;
- _pa_ := (xpart _pa_,max(ypart _pa_,ypart _sa_)) ;
- % we need to compensate for topskip enlarged areas
- if abs(ypart _pa_ - ypart _sa_) > par_line_height :
- (xpart _pa_ + par_hang_indent,ypart _sa_) --
- (xpart _pa_ + par_hang_indent,ypart _pa_) --
- fi
- _pa_
- else :
- (xpart llcorner multipar, ypart _sa_)
- fi
- enddef ;
-
- vardef x_right_bottom_hang (expr i, t) =
- pair _lr_, _sa_, _pa_ ;
- _sa_ := if t : snapped_multi_pos(ulxy[tpos]) else : llcorner multipar fi ;
- if (par_hang_indent<0) and (ra>0) :
- par_hang_after := max(0,ra - estimated_multi_par_height(i, t)) ;
- _lr_ := urcorner multipar ;
- _pa_ := _lr_ shifted (0,-par_hang_after*par_line_height) ;
- _pa_ := (xpart _pa_,max(ypart _pa_,ypart lrcorner multipar)) ;
- _pa_ := (xpart _pa_,max(ypart _pa_,ypart _sa_)) ;
- % we need to compensate for topskip enlarged areas
- _pa_
- if abs(ypart _pa_ - ypart _sa_) > par_line_height :
- -- (xpart _pa_ + par_hang_indent,ypart _pa_)
- -- (xpart _pa_ + par_hang_indent,ypart _sa_)
- fi
- else :
- (xpart lrcorner multipar, ypart _sa_)
+ _pa_
+ else :
+ (xpart llcorner multipar, ypart _sa_)
+ fi
+enddef ;
+
+vardef _pmp_x_right_bottom_hang_ (expr i, t) =
+ pair _lr_, _sa_, _pa_ ;
+ _sa_ := if t : _pmp_snapped_multi_pos_(ulxy[tpos]) else : llcorner multipar fi ;
+ if (par_hang_indent<0) and (ra>0) :
+ par_hang_after := max(0,ra - _pmp_estimated_multi_par_height_(i, t)) ;
+ _lr_ := urcorner multipar ;
+ _pa_ := _lr_ shifted (0,-par_hang_after*par_line_height) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart lrcorner multipar)) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart _sa_)) ;
+ % we need to compensate for topskip enlarged areas
+ _pa_
+ if abs(ypart _pa_ - ypart _sa_) > par_line_height :
+ -- (xpart _pa_ + par_hang_indent,ypart _pa_)
+ -- (xpart _pa_ + par_hang_indent,ypart _sa_)
fi
- enddef ;
+ else :
+ (xpart lrcorner multipar, ypart _sa_)
+ fi
+enddef ;
- def test_multipar =
- multipar := boundingbox multipar ;
- enddef ;
+% def _pmp_test_multipar_ =
+% multipar := boundingbox multipar ;
+% enddef ;
% first loop
@@ -713,7 +714,7 @@ def prepare_multi_pars (expr fn,fx,fy,fw,fh,fd,
TopSkipCorrection := 0 ;
- multipar := set_multipar(i) ;
+ multipar := _pmp_set_multipar_(i) ;
% watch how we compensate for negative indentation
@@ -723,7 +724,8 @@ def prepare_multi_pars (expr fn,fx,fy,fw,fh,fd,
ii := i ;
- if (nxy[tpos]=RealPageNumber) and (InsideTextArea(i,llxy[tpos])) :
+% if (nxy[tpos]=RealPageNumber) and (InsideTextArea(i,llxy[tpos])) :
+ if (nxy[tpos]=RealPageNumber) and (InsideTextArea(i,par_stop_pos)) :
% in same area
@@ -749,9 +751,9 @@ def prepare_multi_pars (expr fn,fx,fy,fw,fh,fd,
llxy[fpos] --
lrxy[tpos] --
%urxy[tpos] --
- snapped_multi_pos(urxy[tpos]) --
+ _pmp_snapped_multi_pos_(urxy[tpos]) --
%ulxy[fpos] --
- snapped_multi_pos(ulxy[fpos]) --
+ _pmp_snapped_multi_pos_(ulxy[fpos]) --
cycle ;
save_multipar (i,1,multipar) ;
@@ -763,9 +765,9 @@ def prepare_multi_pars (expr fn,fx,fy,fw,fh,fd,
multipar := if obey_multi_par_hang :
- right_bottom_hang(true) --
- right_top_hang(true) --
- snapped_multi_pos(urxy[fpos]) --
+ _pmp_right_bottom_hang_(true) --
+ _pmp_right_top_hang_(true) --
+ _pmp_snapped_multi_pos_(urxy[fpos]) --
lrxy[fpos] --
else :
@@ -773,26 +775,26 @@ def prepare_multi_pars (expr fn,fx,fy,fw,fh,fd,
llxy[fpos] --
(xpart urcorner multipar, ypart llxy[fpos]) --
(xpart urcorner multipar, ypart ulxy[fpos]) --
- snapped_multi_pos(ulxy[fpos]) --
+ _pmp_snapped_multi_pos_(ulxy[fpos]) --
fi cycle ;
save_multipar (i,1,multipar) ;
- multipar := set_multipar(i) ;
+ multipar := _pmp_set_multipar_(i) ;
multipar := if obey_multi_par_hang :
- left_bottom_hang(true) --
+ _pmp_left_bottom_hang_(true) --
llxy[tpos] --
- snapped_multi_pos(ulxy[tpos]) --
- left_top_hang(true) --
+ _pmp_snapped_multi_pos_(ulxy[tpos]) --
+ _pmp_left_top_hang_(true) --
else :
(xpart llcorner multipar, ypart llxy[tpos]) --
llxy[tpos] --
- snapped_multi_pos(ulxy[tpos]) --
+ _pmp_snapped_multi_pos_(ulxy[tpos]) --
(xpart llcorner multipar, ypart ulxy[tpos]) --
fi cycle ;
@@ -803,27 +805,27 @@ def prepare_multi_pars (expr fn,fx,fy,fw,fh,fd,
multipar := if obey_multi_par_hang :
- left_bottom_hang(true) --
+ _pmp_left_bottom_hang_(true) --
llxy[tpos] --
%ulxy[tpos] --
- snapped_multi_pos(ulxy[tpos]) --
- right_bottom_hang(true) --
- right_top_hang(true) --
+ _pmp_snapped_multi_pos_(ulxy[tpos]) --
+ _pmp_right_bottom_hang_(true) --
+ _pmp_right_top_hang_(true) --
%urxy[fpos] --
- snapped_multi_pos(urxy[fpos]) --
+ _pmp_snapped_multi_pos_(urxy[fpos]) --
lrxy[fpos] --
- left_top_hang(true) --
+ _pmp_left_top_hang_(true) --
else :
(xpart llcorner multipar, ypart llxy[tpos]) --
llxy[tpos] --
%ulxy[tpos] --
- snapped_multi_pos(ulxy[tpos]) --
+ _pmp_snapped_multi_pos_(ulxy[tpos]) --
(xpart lrcorner multipar, ypart ulxy[tpos]) --
(xpart urcorner multipar, ypart urxy[fpos]) --
%urxy[fpos] --
- snapped_multi_pos(urxy[fpos]) --
+ _pmp_snapped_multi_pos_(urxy[fpos]) --
lrxy[fpos] --
(xpart ulcorner multipar, ypart lrxy[fpos]) --
@@ -837,13 +839,13 @@ def prepare_multi_pars (expr fn,fx,fy,fw,fh,fd,
multipar := if obey_multi_par_hang :
- left_bottom_hang(false) --
- right_bottom_hang(false) --
- right_top_hang(false) --
+ _pmp_left_bottom_hang_(false) --
+ _pmp_right_bottom_hang_(false) --
+ _pmp_right_top_hang_(false) --
%urxy[fpos] --
- snapped_multi_pos(urxy[fpos]) --
+ _pmp_snapped_multi_pos_(urxy[fpos]) --
lrxy[fpos] --
- left_top_hang(false) --
+ _pmp_left_top_hang_(false) --
else :
@@ -851,7 +853,7 @@ def prepare_multi_pars (expr fn,fx,fy,fw,fh,fd,
lrcorner multipar --
(xpart urcorner multipar, ypart urxy[fpos]) --
%urxy[fpos] --
- snapped_multi_pos(urxy[fpos]) --
+ _pmp_snapped_multi_pos_(urxy[fpos]) --
lrxy[fpos] --
(xpart ulcorner multipar, ypart lrxy[fpos]) --
@@ -861,7 +863,8 @@ def prepare_multi_pars (expr fn,fx,fy,fw,fh,fd,
fi ;
- elseif (nxy[tpos]=RealPageNumber) and (InsideTextArea(i,llxy[tpos])) :
+% elseif (nxy[tpos]=RealPageNumber) and (InsideTextArea(i,llxy[tpos])) :
+ elseif (nxy[tpos]=RealPageNumber) and (InsideTextArea(i,par_stop_pos)) :
% last one in chain
@@ -870,12 +873,12 @@ def prepare_multi_pars (expr fn,fx,fy,fw,fh,fd,
if obey_multi_par_hang and obey_multi_par_more :
multipar :=
- x_left_top_hang(i,true) --
- x_right_top_hang(i,true) --
- x_right_bottom_hang(i,true) --
- snapped_multi_pos(ulxy[tpos]) --
+ _pmp_x_left_top_hang_(i,true) --
+ _pmp_x_right_top_hang_(i,true) --
+ _pmp_x_right_bottom_hang_(i,true) --
+ _pmp_snapped_multi_pos_(ulxy[tpos]) --
llxy[tpos] --
- x_left_bottom_hang(i,true) --
+ _pmp_x_left_bottom_hang_(i,true) --
cycle ;
else :
@@ -884,7 +887,7 @@ def prepare_multi_pars (expr fn,fx,fy,fw,fh,fd,
ulcorner multipar --
urcorner multipar --
(xpart lrcorner multipar, ypart urxy[tpos]) --
- snapped_multi_pos(ulxy[tpos]) --
+ _pmp_snapped_multi_pos_(ulxy[tpos]) --
llxy[tpos] --
(xpart llcorner multipar, ypart llxy[tpos]) --
cycle ;
@@ -917,15 +920,15 @@ def prepare_multi_pars (expr fn,fx,fy,fw,fh,fd,
((nxy[fpos]<RealPageNumber) and (nxy[tpos]>RealPageNumber))
:
- multipar := set_multipar(i) ;
+ multipar := _pmp_set_multipar_(i) ;
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) --
+ _pmp_x_left_top_hang_(i,false) --
+ _pmp_x_right_top_hang_(i,false) --
+ _pmp_x_right_bottom_hang_(i,false) --
+ _pmp_x_left_bottom_hang_(i,false) --
cycle ;
fi ;
diff --git a/metapost/context/base/mp-mlib.mp b/metapost/context/base/mp-mlib.mp
index bf2372ca3..f6229f2ff 100644
--- a/metapost/context/base/mp-mlib.mp
+++ b/metapost/context/base/mp-mlib.mp
@@ -89,44 +89,44 @@ 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 ;
+numeric labxf.l ; labxf.l = labxf.lft ;
+numeric labxf.r ; labxf.r = labxf.rt ;
+numeric labxf.b ; labxf.b = labxf.bot ;
+numeric labxf.t ; labxf.t = labxf.top ;
+numeric labxf.l_t ; labxf.l_t = labxf.ulft ;
+numeric labxf.r_t ; labxf.r_t = labxf.urt ;
+numeric labxf.l_b ; labxf.l_b = labxf.llft ;
+numeric labxf.r_b ; labxf.r_b = labxf.lrt ;
+numeric labxf.t_l ; labxf.t_l = labxf.ulft ;
+numeric labxf.t_r ; labxf.t_r = labxf.urt ;
+numeric labxf.b_l ; labxf.b_l = labxf.llft ;
+numeric 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 ;
+numeric labyf.l ; labyf.l = labyf.lft ;
+numeric labyf.r ; labyf.r = labyf.rt ;
+numeric labyf.b ; labyf.b = labyf.bot ;
+numeric labyf.t ; labyf.t = labyf.top ;
+numeric labyf.l_t ; labyf.l_t = labyf.ulft ;
+numeric labyf.r_t ; labyf.r_t = labyf.urt ;
+numeric labyf.l_b ; labyf.l_b = labyf.llft ;
+numeric labyf.r_b ; labyf.r_b = labyf.lrt ;
+numeric labyf.t_l ; labyf.t_l = labyf.ulft ;
+numeric labyf.t_r ; labyf.t_r = labyf.urt ;
+numeric labyf.b_l ; labyf.b_l = labyf.llft ;
+numeric 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 ;
+numeric labtype.l ; labtype.l = labtype.lft ;
+numeric labtype.r ; labtype.r = labtype.rt ;
+numeric labtype.b ; labtype.b = labtype.bot ;
+numeric labtype.t ; labtype.t = labtype.top ;
+numeric labtype.l_t ; labtype.l_t = labtype.ulft ;
+numeric labtype.r_t ; labtype.r_t = labtype.urt ;
+numeric labtype.l_b ; labtype.l_b = labtype.llft ;
+numeric labtype.r_b ; labtype.r_b = labtype.lrt ;
+numeric labtype.t_l ; labtype.t_l = labtype.ulft ;
+numeric labtype.t_r ; labtype.t_r = labtype.urt ;
+numeric labtype.b_l ; labtype.b_l = labtype.llft ;
+numeric labtype.b_r ; labtype.b_r = labtype.lrt ;
vardef thetextext@#(expr p,z) = % adapted copy of thelabel@
if string p :
diff --git a/metapost/context/base/mp-page.mp b/metapost/context/base/mp-page.mp
index 60bfb1417..4f6569d33 100644
--- a/metapost/context/base/mp-page.mp
+++ b/metapost/context/base/mp-page.mp
@@ -123,7 +123,7 @@ vardef InsideSavedTextArea (expr _i_, _xy_) =
(round(ypart _xy_) <= round(ypart urcorner SavedTextAreas[_i_])) )
enddef ;
-vardef InsideSomeTextArea(expr _xy_) =
+vardef InsideSomeTextArea (expr _xy_) =
save ok ; boolean ok ; ok := false ;
for i := 1 upto NOfTextAreas :
if InsideTextArea(i,_xy_) : ok := true ; fi ;
@@ -132,7 +132,7 @@ vardef InsideSomeTextArea(expr _xy_) =
ok
enddef ;
-vardef InsideSomeSavedTextArea(expr _xy_) =
+vardef InsideSomeSavedTextArea (expr _xy_) =
save ok ; boolean ok ; ok := false ;
for i := 1 upto NOfSavedTextAreas :
if InsideSavedTextArea(i,_xy_) : ok := true ; fi ;
diff --git a/scripts/context/lua/luatools.lua b/scripts/context/lua/luatools.lua
deleted file mode 100644
index 1d87322c1..000000000
--- a/scripts/context/lua/luatools.lua
+++ /dev/null
@@ -1,8185 +0,0 @@
-#!/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.mkiv",
- 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, lower = string.sub, string.gsub, string.find, string.match, string.gmatch, string.format, string.char, string.byte, string.rep, string.lower
-local lpegmatch = lpeg.match
-
--- some functions may disappear as they are not used anywhere
-
-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:unquote()
---~ if find(self,"^[\'\"]") then
---~ return sub(self,2,-2)
---~ else
---~ return self
---~ end
---~ end
-
-function string:quote() -- we could use format("%q")
- return format("%q",self)
-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() -- the .- is quite efficient
---~ -- return match(self,"^%s*(.-)%s*$") or ""
---~ -- return match(self,'^%s*(.*%S)') or '' -- posted on lua list
---~ return find(s,'^%s*$') and '' or match(s,'^%s*(.*%S)')
---~ end
-
-do -- roberto's variant:
- local space = lpeg.S(" \t\v\n")
- local nospace = 1 - space
- local stripper = space^0 * lpeg.C((space^0 * nospace^1)^0)
- function string.strip(str)
- return lpegmatch(stripper,str) or ""
- end
-end
-
-function string:is_empty()
- return not find(self,"%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, sub(str,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(sub(str,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 .. rep(chr or " ",m)
- else
- return self
- end
-end
-
-function string:lpadd(n,chr)
- local m = n-#self
- if m > 0 then
- return 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
-
-local simple_escapes = {
- ["-"] = "%-",
- ["."] = "%.",
- ["?"] = ".",
- ["*"] = ".*",
-}
-
-function string:simpleesc()
- return (gsub(self,".",simple_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 lpegmatch(pattern,self)
-end
-
---~ local t = {
---~ "1234567123456712345671234567",
---~ "a\tb\tc",
---~ "aa\tbb\tcc",
---~ "aaa\tbbb\tccc",
---~ "aaaa\tbbbb\tcccc",
---~ "aaaaa\tbbbbb\tccccc",
---~ "aaaaaa\tbbbbbb\tcccccc",
---~ }
---~ for k,v do
---~ print(string.tabtospace(t[k]))
---~ 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
-
-function string:compactlong() -- strips newlines and leading spaces
- self = gsub(self,"[\n\r]+ *","")
- self = gsub(self,"^ *","")
- return self
-end
-
-function string:striplong() -- strips newlines and leading spaces
- self = gsub(self,"^%s*","")
- self = gsub(self,"[\n\r]+ *","\n")
- return self
-end
-
-function string:topattern(lowercase,strict)
- if lowercase then
- self = lower(self)
- end
- self = gsub(self,".",simple_escapes)
- if self == "" then
- self = ".*"
- elseif strict then
- self = "^" .. self .. "$"
- end
- return self
-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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local lpeg = require("lpeg")
-
-lpeg.patterns = lpeg.patterns or { } -- so that we can share
-local patterns = lpeg.patterns
-
-local P, R, S, Ct, C, Cs, Cc, V = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.V
-local match = lpeg.match
-
-local digit, sign = R('09'), S('+-')
-local cr, lf, crlf = P("\r"), P("\n"), P("\r\n")
-local utf8byte = R("\128\191")
-
-patterns.utf8byte = utf8byte
-patterns.utf8one = R("\000\127")
-patterns.utf8two = R("\194\223") * utf8byte
-patterns.utf8three = R("\224\239") * utf8byte * utf8byte
-patterns.utf8four = R("\240\244") * utf8byte * utf8byte * utf8byte
-
-patterns.digit = digit
-patterns.sign = sign
-patterns.cardinal = sign^0 * digit^1
-patterns.integer = sign^0 * digit^1
-patterns.float = sign^0 * digit^0 * P('.') * digit^1
-patterns.number = patterns.float + patterns.integer
-patterns.oct = P("0") * R("07")^1
-patterns.octal = patterns.oct
-patterns.HEX = P("0x") * R("09","AF")^1
-patterns.hex = P("0x") * R("09","af")^1
-patterns.hexadecimal = P("0x") * R("09","AF","af")^1
-patterns.lowercase = R("az")
-patterns.uppercase = R("AZ")
-patterns.letter = patterns.lowercase + patterns.uppercase
-patterns.space = S(" ")
-patterns.eol = S("\n\r")
-patterns.spacer = S(" \t\f\v") -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
-patterns.newline = crlf + cr + lf
-patterns.nonspace = 1 - patterns.space
-patterns.nonspacer = 1 - patterns.spacer
-patterns.whitespace = patterns.eol + patterns.spacer
-patterns.nonwhitespace = 1 - patterns.whitespace
-patterns.utf8 = patterns.utf8one + patterns.utf8two + patterns.utf8three + patterns.utf8four
-patterns.utfbom = P('\000\000\254\255') + P('\255\254\000\000') + P('\255\254') + P('\254\255') + P('\239\187\191')
-
-function lpeg.anywhere(pattern) --slightly adapted from website
- return P { P(pattern) + 1 * V(1) } -- why so complex?
-end
-
-function lpeg.splitter(pattern, action)
- return (((1-P(pattern))^1)/action+1)^0
-end
-
-local spacing = patterns.spacer^0 * patterns.newline -- sort of strip
-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 match(capture,self)
-end
-
-patterns.textline = content
-
---~ local p = lpeg.splitat("->",false) print(match(p,"oeps->what->more")) -- oeps what more
---~ local p = lpeg.splitat("->",true) print(match(p,"oeps->what->more")) -- oeps what->more
---~ local p = lpeg.splitat("->",false) print(match(p,"oeps")) -- oeps
---~ local p = lpeg.splitat("->",true) print(match(p,"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 lpeg.split(separator,str)
- local c = cache[separator]
- if not c then
- c = Ct(splitat(separator))
- cache[separator] = c
- end
- return match(c,str)
-end
-
-function string:split(separator)
- local c = cache[separator]
- if not c then
- c = Ct(splitat(separator))
- cache[separator] = c
- end
- return match(c,self)
-end
-
-lpeg.splitters = cache
-
-local cache = { }
-
-function lpeg.checkedsplit(separator,str)
- local c = cache[separator]
- if not c then
- separator = P(separator)
- local other = C((1 - separator)^0)
- c = Ct(separator^0 * other * (separator^1 * other)^0)
- cache[separator] = c
- end
- return match(c,str)
-end
-
-function string:checkedsplit(separator)
- local c = cache[separator]
- if not c then
- separator = P(separator)
- local other = C((1 - separator)^0)
- c = Ct(separator^0 * other * (separator^1 * other)^0)
- cache[separator] = c
- end
- return match(c,self)
-end
-
---~ function lpeg.append(list,pp)
---~ local p = pp
---~ for l=1,#list do
---~ if p then
---~ p = p + P(list[l])
---~ else
---~ p = P(list[l])
---~ end
---~ end
---~ return p
---~ end
-
---~ from roberto's site:
-
-local f1 = string.byte
-
-local function f2(s) local c1, c2 = f1(s,1,2) return c1 * 64 + c2 - 12416 end
-local function f3(s) local c1, c2, c3 = f1(s,1,3) return (c1 * 64 + c2) * 64 + c3 - 925824 end
-local function f4(s) local c1, c2, c3, c4 = f1(s,1,4) return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168 end
-
-patterns.utf8byte = patterns.utf8one/f1 + patterns.utf8two/f2 + patterns.utf8three/f3 + patterns.utf8four/f4
-
-
-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.mkiv",
- 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, match = string.format, string.find, string.gsub, string.lower, string.dump, string.match
-local getmetatable, setmetatable = getmetatable, setmetatable
-local type, next, tostring, tonumber, ipairs = type, next, tostring, tonumber, ipairs
-local unpack = unpack or table.unpack
-
-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
-
-function table.keys(t)
- local k = { }
- for key, _ in next, t do
- k[#k+1] = key
- end
- return k
-end
-
-local function compare(a,b)
- return (tostring(a) < tostring(b))
-end
-
-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,compare)
- 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.sortedhash(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
-
-table.sortedpairs = table.sortedhash
-
-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) -- obolete, use inline code instead
- return not t or not next(t)
-end
-
-function table.one_entry(t) -- obolete, use inline code instead
- local n = next(t)
- return n and not next(t,n)
-end
-
---~ function table.starts_at(t) -- obsolete, not nice
---~ 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) )
-
--- problem: there no good number_to_string converter with the best resolution
-
-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
- -- we could check for k (index) being number (cardinal)
- if root and next(root) then
- local first, last = nil, 0 -- #root cannot be trusted here (will be ok in 5.2 when ipairs is gone)
- 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)) -- %.99g
- end
- elseif t == "string" then
- if reduce and tonumber(v) 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)) -- %.99g
- --~ 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)) -- %.99g
- 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)) -- %.99g
- end
- else
- if hexify then
- handle(format("%s [%q]=0x%04X,",depth,k,v))
- else
- handle(format("%s [%q]=%s,",depth,k,v)) -- %.99g
- end
- end
- elseif t == "string" then
- if reduce and tonumber(v) 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) -- is this used? meybe a variant with next, ...
- 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
-
--- a better one:
-
-local function flattened(t,f)
- if not f then
- f = { }
- end
- for k, v in next, t do
- if type(v) == "table" then
- flattened(v,f)
- else
- f[k] = v
- end
- end
- return f
-end
-
-table.flattened = flattened
-
--- 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 and b and #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 }) -- why not __index = p ?
- 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.insert_before_value(t,value,extra)
- for i=1,#t do
- if t[i] == extra then
- remove(t,i)
- end
- end
- for i=1,#t do
- if t[i] == value then
- insert(t,i,extra)
- return
- end
- end
- insert(t,1,extra)
-end
-
-function table.insert_after_value(t,value,extra)
- for i=1,#t do
- if t[i] == extra then
- remove(t,i)
- end
- end
- for i=1,#t do
- if t[i] == value then
- insert(t,i+1,extra)
- return
- end
- end
- insert(t,#t+1,extra)
-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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local byte, find, gsub = string.byte, string.find, string.gsub
-
-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
- -- collectgarbage("step") -- sometimes makes a big difference in mem consumption
- 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 or "")
- 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 = gsub(answer,"^%s*(.*)%s*$","%1")
- if answer == "" and default then
- return default
- elseif not options then
- return answer
- else
- for k=1,#options do
- if options[k] == answer then
- return answer
- end
- end
- local pattern = "^" .. answer
- for k=1,#options do
- local v = options[k]
- if find(v,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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local tostring = tostring
-local format, floor, insert, match = string.format, math.floor, table.insert, string.match
-local lpegmatch = lpeg.match
-
-number = number or { }
-
--- a,b,c,d,e,f = number.toset(100101)
-
-function number.toset(n)
- return match(tostring(n),"(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)")
-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 lpegmatch(one,tostring(n))
-end
-
-function number.bits(n,zero)
- local t, i = { }, (zero and 0) or 1
- while n > 0 do
- local m = n % 2
- if m > 0 then
- insert(t,1,i)
- end
- n = floor(n/2)
- i = i + 1
- end
- return t
-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.mkiv",
- 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
-local next, type = next, type
-
-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 next, t do
- if v then
- -- why bother about the leading space
- s = s .. " " .. k
- end
- end
- local n = nums[s]
- if not n then
- n = #tabs + 1
- tabs[n] = t
- nums[s] = n
- end
- return n
- else
- return 0
- end
-end
-
-function set.totable(n)
- if n == 0 then
- return { }
- else
- return tabs[n] or { }
- end
-end
-
-function set.tolist(n)
- if n == 0 or not tabs[n] then
- return ""
- else
- local t = { }
- for k, v in next, tabs[n] do
- if v then
- t[#t+1] = k
- end
- end
- return concat(t," ")
- 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-lib.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- maybe build io.flush in os.execute
-
-local find, format, gsub = string.find, string.format, string.gsub
-local random, ceil = math.random, math.ceil
-
-local execute, spawn, exec, ioflush = os.execute, os.spawn or os.execute, os.exec or os.execute, io.flush
-
-function os.execute(...) ioflush() return execute(...) end
-function os.spawn (...) ioflush() return spawn (...) end
-function os.exec (...) ioflush() return exec (...) end
-
-function os.resultof(command)
- ioflush() -- else messed up logging
- local handle = io.popen(command,"r")
- if not handle then
- -- print("unknown command '".. command .. "' in os.resultof")
- return ""
- else
- return handle:read("*all") or ""
- end
-end
-
---~ os.type : windows | unix (new, we already guessed os.platform)
---~ os.name : windows | msdos | linux | macosx | solaris | .. | generic (new)
---~ os.platform : extended os.name with architecture
-
-if not io.fileseparator then
- if find(os.getenv("PATH"),";") then
- io.fileseparator, io.pathseparator, os.type = "\\", ";", os.type or "mswin"
- else
- io.fileseparator, io.pathseparator, os.type = "/" , ":", os.type or "unix"
- end
-end
-
-os.type = os.type or (io.pathseparator == ";" and "windows") or "unix"
-os.name = os.name or (os.type == "windows" and "mswin" ) or "linux"
-
-if os.type == "windows" then
- os.libsuffix, os.binsuffix = 'dll', 'exe'
-else
- os.libsuffix, os.binsuffix = 'so', ''
-end
-
-function os.launch(str)
- if os.type == "windows" then
- os.execute("start " .. str) -- os.spawn ?
- else
- os.execute(str .. " &") -- os.spawn ?
- 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()))
-
--- no need for function anymore as we have more clever code and helpers now
--- this metatable trickery might as well disappear
-
-os.resolvers = os.resolvers or { }
-
-local resolvers = os.resolvers
-
-local osmt = getmetatable(os) or { __index = function(t,k) t[k] = "unset" return "unset" end } -- maybe nil
-local osix = osmt.__index
-
-osmt.__index = function(t,k)
- return (resolvers[k] or osix)(t,k)
-end
-
-setmetatable(os,osmt)
-
-if not os.setenv then
-
- -- we still store them but they won't be seen in
- -- child processes although we might pass them some day
- -- using command concatination
-
- local env, getenv = { }, os.getenv
-
- function os.setenv(k,v)
- env[k] = v
- end
-
- function os.getenv(k)
- return env[k] or getenv(k)
- end
-
-end
-
--- we can use HOSTTYPE on some platforms
-
-local name, platform = os.name or "linux", os.getenv("MTX_PLATFORM") or ""
-
-local function guess()
- local architecture = os.resultof("uname -m") or ""
- if architecture ~= "" then
- return architecture
- end
- architecture = os.getenv("HOSTTYPE") or ""
- if architecture ~= "" then
- return architecture
- end
- return os.resultof("echo $HOSTTYPE") or ""
-end
-
-if platform ~= "" then
-
- os.platform = platform
-
-elseif os.type == "windows" then
-
- -- we could set the variable directly, no function needed here
-
- function os.resolvers.platform(t,k)
- local platform, architecture = "", os.getenv("PROCESSOR_ARCHITECTURE") or ""
- if find(architecture,"AMD64") then
- platform = "mswin-64"
- else
- platform = "mswin"
- end
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-
-elseif name == "linux" then
-
- function os.resolvers.platform(t,k)
- -- we sometims have HOSTTYPE set so let's check that first
- local platform, architecture = "", os.getenv("HOSTTYPE") or os.resultof("uname -m") or ""
- if find(architecture,"x86_64") then
- platform = "linux-64"
- elseif find(architecture,"ppc") then
- platform = "linux-ppc"
- else
- platform = "linux"
- end
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-
-elseif name == "macosx" then
-
- --[[
- Identifying the architecture of OSX is quite a mess and this
- is the best we can come up with. For some reason $HOSTTYPE is
- a kind of pseudo environment variable, not known to the current
- environment. And yes, uname cannot be trusted either, so there
- is a change that you end up with a 32 bit run on a 64 bit system.
- Also, some proper 64 bit intel macs are too cheap (low-end) and
- therefore not permitted to run the 64 bit kernel.
- ]]--
-
- function os.resolvers.platform(t,k)
- -- local platform, architecture = "", os.getenv("HOSTTYPE") or ""
- -- if architecture == "" then
- -- architecture = os.resultof("echo $HOSTTYPE") or ""
- -- end
- local platform, architecture = "", os.resultof("echo $HOSTTYPE") or ""
- if architecture == "" then
- -- print("\nI have no clue what kind of OSX you're running so let's assume an 32 bit intel.\n")
- platform = "osx-intel"
- elseif find(architecture,"i386") then
- platform = "osx-intel"
- elseif find(architecture,"x86_64") then
- platform = "osx-64"
- else
- platform = "osx-ppc"
- end
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-
-elseif name == "sunos" then
-
- function os.resolvers.platform(t,k)
- local platform, architecture = "", os.resultof("uname -m") or ""
- if find(architecture,"sparc") then
- platform = "solaris-sparc"
- else -- if architecture == 'i86pc'
- platform = "solaris-intel"
- end
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-
-elseif name == "freebsd" then
-
- function os.resolvers.platform(t,k)
- local platform, architecture = "", os.resultof("uname -m") or ""
- if find(architecture,"amd64") then
- platform = "freebsd-amd64"
- else
- platform = "freebsd"
- end
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-
-elseif name == "kfreebsd" then
-
- function os.resolvers.platform(t,k)
- -- we sometims have HOSTTYPE set so let's check that first
- local platform, architecture = "", os.getenv("HOSTTYPE") or os.resultof("uname -m") or ""
- if find(architecture,"x86_64") then
- platform = "kfreebsd-64"
- else
- platform = "kfreebsd-i386"
- end
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-
-else
-
- -- platform = "linux"
- -- os.setenv("MTX_PLATFORM",platform)
- -- os.platform = platform
-
- function os.resolvers.platform(t,k)
- local platform = "linux"
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-
-end
-
--- beware, we set the randomseed
-
--- from wikipedia: Version 4 UUIDs use a scheme relying only on random numbers. This algorithm sets the
--- version number as well as two reserved bits. All other bits are set using a random or pseudorandom
--- data source. Version 4 UUIDs have the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx with hexadecimal
--- digits x and hexadecimal digits 8, 9, A, or B for y. e.g. f47ac10b-58cc-4372-a567-0e02b2c3d479.
---
--- as we don't call this function too often there is not so much risk on repetition
-
-local t = { 8, 9, "a", "b" }
-
-function os.uuid()
- return format("%04x%04x-4%03x-%s%03x-%04x-%04x%04x%04x",
- random(0xFFFF),random(0xFFFF),
- random(0x0FFF),
- t[ceil(random(4))] or 8,random(0x0FFF),
- random(0xFFFF),
- random(0xFFFF),random(0xFFFF),random(0xFFFF)
- )
-end
-
-local d
-
-function os.timezone(delta)
- d = d or tonumber(tonumber(os.date("%H")-os.date("!%H")))
- if delta then
- if d > 0 then
- return format("+%02i:00",d)
- else
- return format("-%02i:00",-d)
- end
- else
- return 1
- end
-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.mkiv",
- 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, sub, char = string.find, string.gmatch, string.match, string.gsub, string.sub, string.char
-local lpegmatch = lpeg.match
-
-function file.removesuffix(filename)
- return (gsub(filename,"%.[%a%d]+$",""))
-end
-
-function file.addsuffix(filename, suffix)
- if not suffix or suffix == "" then
- return filename
- elseif 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,default)
- return match(name,"^.+%.([^/\\]-)$") or default or ""
-end
-
-file.suffix = file.extname
-
---~ 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
-
-local trick_1 = char(1)
-local trick_2 = "^" .. trick_1 .. "/+"
-
-function file.join(...)
- local lst = { ... }
- local a, b = lst[1], lst[2]
- if a == "" then
- lst[1] = trick_1
- elseif b and find(a,"^/+$") and find(b,"^/") then
- lst[1] = ""
- lst[2] = gsub(b,"^/+","")
- end
- local pth = concat(lst,"/")
- 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
- pth = gsub(pth,trick_2,"")
- return (gsub(pth,"//+","/"))
-end
-
---~ print(file.join("//","/y"))
---~ print(file.join("/","/y"))
---~ print(file.join("","/y"))
---~ print(file.join("/x/","/y"))
---~ 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.iswritable(name)
- local a = lfs.attributes(name) or lfs.attributes(file.dirname(name,"."))
- return a and sub(a.permissions,2,2) == "w"
-end
-
-function file.isreadable(name)
- local a = lfs.attributes(name)
- return a and sub(a.permissions,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
-
-local checkedsplit = string.checkedsplit
-
-function file.split_path(str,separator)
- str = gsub(str,"\\","/")
- return checkedsplit(str,separator or io.pathseparator)
-end
-
-function file.join_path(tab)
- return concat(tab,io.pathseparator) -- can have trailing //
-end
-
--- we can hash them weakly
-
-function file.collapse_path(str)
- str = gsub(str,"\\","/")
- if find(str,"/") then
- str = gsub(str,"^%./",(gsub(lfs.currentdir(),"\\","/")) .. "/") -- ./xx in qualified
- 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,"^%./","") -- ./xx in qualified
- str = gsub(str,"/%.$","")
- end
- if str == "" then str = "." end
- return str
-end
-
---~ print(file.collapse_path("/a"))
---~ 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 lpegmatch(pattern,name) or ""
---~ end
-
---~ local pattern = lpeg.Cs(((period * noperiod^1 * -1)/"" + 1)^1)
-
---~ function file.removesuffix(name)
---~ return lpegmatch(pattern,name)
---~ end
-
---~ local pattern = (noslashes^0 * slashes)^1 * lpeg.C(noslashes^1) * -1
-
---~ function file.basename(name)
---~ return lpegmatch(pattern,name) or name
---~ end
-
---~ local pattern = (noslashes^0 * slashes)^1 * lpeg.Cp() * noslashes^1 * -1
-
---~ function file.dirname(name)
---~ local p = lpegmatch(pattern,name)
---~ if p then
---~ return sub(name,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 = lpegmatch(pattern,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 = lpegmatch(pattern,name)
---~ if p then
---~ return sub(name,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 = lpegmatch(pattern,name)
---~ if b then
---~ return sub(name,a,b-2)
---~ elseif a then
---~ return sub(name,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 lpegmatch(qualified,filename) ~= nil
-end
-
-function file.is_rootbased_path(filename)
- return lpegmatch(rootbased,filename) ~= nil
-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 lpegmatch(pattern,str)
-end
-
--- function test(t) for k, v in next, 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" }
-
---~ -- todo:
---~
---~ if os.type == "windows" then
---~ local currentdir = lfs.currentdir
---~ function lfs.currentdir()
---~ return (gsub(currentdir(),"\\","/"))
---~ end
---~ 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 (gsub(data,"%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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local char, gmatch, gsub = string.char, string.gmatch, string.gsub
-local tonumber, type = tonumber, type
-local lpegmatch = lpeg.match
-
--- 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)
-
--- we assume schemes with more than 1 character (in order to avoid problems with windows disks)
-
-local scheme = lpeg.Cs((escaped+(1-colon-slash-qmark-hash))^2) * 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)
-
--- todo: reconsider Ct as we can as well have five return values (saves a table)
--- so we can have two parsers, one with and one without
-
-function url.split(str)
- return (type(str) == "string" and lpegmatch(parser,str)) or str
-end
-
--- todo: cache them
-
-function url.hashed(str)
- local s = url.split(str)
- local somescheme = s[1] ~= ""
- return {
- scheme = (somescheme and s[1]) or "file",
- authority = s[2],
- path = s[3],
- query = s[4],
- fragment = s[5],
- original = str,
- noscheme = not somescheme,
- }
-end
-
-function url.hasscheme(str)
- return url.split(str)[1] ~= ""
-end
-
-function url.addscheme(str,scheme)
- return (url.hasscheme(str) and str) or ((scheme or "file:///") .. str)
-end
-
-function url.construct(hash)
- local fullurl = hash.sheme .. "://".. hash.authority .. hash.path
- if hash.query then
- fullurl = fullurl .. "?".. hash.query
- end
- if hash.fragment then
- fullurl = fullurl .. "?".. hash.fragment
- end
- return fullurl
-end
-
-function url.filename(filename)
- local t = url.hashed(filename)
- return (t.scheme == "file" and (gsub(t.path,"^/([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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- dir.expand_name will be merged with cleanpath and collapsepath
-
-local type = type
-local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub
-local lpegmatch = lpeg.match
-
-dir = dir or { }
-
--- handy
-
-function dir.current()
- return (gsub(lfs.currentdir(),"\\","/"))
-end
-
--- 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 function collect_pattern(path,patt,recurse,result)
- local ok, scanner
- result = result or { }
- 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 attr = attributes(full)
- local mode = attr.mode
- if mode == 'file' then
- if find(full,patt) then
- result[name] = attr
- end
- elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
- attr.list = collect_pattern(full,patt,recurse)
- result[name] = attr
- end
- end
- end
- return result
-end
-
-dir.collect_pattern = collect_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(t) == "function" then
- if type(str) == "table" then
- for s=1,#str do
- glob(str[s],t)
- end
- elseif lfs.isfile(str) then
- t(str)
- else
- local split = lpegmatch(pattern,str)
- if split then
- local root, path, base = split[1], split[2], split[3]
- local recurse = find(base,"%*%*")
- local start = root .. path
- local result = lpegmatch(filter,start .. base)
- glob_pattern(start,result,recurse,t)
- end
- end
- else
- 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 = lpegmatch(pattern,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 = lpegmatch(filter,start .. base)
- glob_pattern(start,result,recurse,action)
- return t
- else
- return { }
- end
- 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 -- os.type == "windows"
-
- function dir.mkdirs(...)
- local str, pth, t = "", "", { ... }
- for i=1,#t do
- local s = t[i]
- 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 = match(str,"^(//)(//*)(.*)$")
- if first then
- -- empty network path == local path
- else
- first, last = match(str,"^(//)/*(.-)$")
- if first then
- middle, last = match(str,"([^/]+)/+(.-)$")
- if middle then
- pth = "//" .. middle
- else
- pth = "//" .. last
- last = ""
- end
- else
- first, middle, last = match(str,"^([a-zA-Z]:)(/*)(.-)$")
- if first then
- pth, drive = first .. middle, true
- else
- middle, last = match(str,"^(/*)(.-)$")
- 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) -- will be merged with cleanpath and collapsepath
- local first, nothing, last = match(str,"^(//)(//*)(.*)$")
- if first then
- first = dir.current() .. "/"
- end
- if not first then
- first, last = match(str,"^(//)/*(.*)$")
- end
- if not first then
- first, last = match(str,"^([a-zA-Z]:)(.*)$")
- if first and not find(last,"^/") then
- local d = lfs.currentdir()
- if lfs.chdir(first) then
- first = dir.current()
- end
- lfs.chdir(d)
- end
- end
- if not first then
- first, last = dir.current(), str
- end
- last = gsub(last,"//","/")
- last = gsub(last,"/%./","/")
- last = gsub(last,"^/*","")
- first = gsub(first,"/*$","")
- if last == "" then
- return first
- else
- return first .. "/" .. last
- end
- end
-
-else
-
- function dir.mkdirs(...)
- local str, pth, t = "", "", { ... }
- for i=1,#t do
- local s = t[i]
- if s ~= "" then
- if str ~= "" then
- str = str .. "/" .. s
- else
- str = s
- end
- end
- end
- str = gsub(str,"/+","/")
- 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) -- will be merged with cleanpath and collapsepath
- if not find(str,"^/") then
- str = lfs.currentdir() .. "/" .. str
- end
- str = gsub(str,"//","/")
- str = gsub(str,"/%./","/")
- 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.mkiv",
- 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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-if not unicode then
-
- unicode = { utf8 = { } }
-
- local floor, char = math.floor, string.char
-
- function unicode.utf8.utfchar(n)
- if n < 0x80 then
- return char(n)
- elseif n < 0x800 then
- return char(0xC0 + floor(n/0x40)) .. char(0x80 + (n % 0x40))
- elseif n < 0x10000 then
- return char(0xE0 + floor(n/0x1000)) .. char(0x80 + (floor(n/0x40) % 0x40)) .. char(0x80 + (n % 0x40))
- elseif n < 0x40000 then
- return char(0xF0 + floor(n/0x40000)) .. char(0x80 + floor(n/0x1000)) .. char(0x80 + (floor(n/0x40) % 0x40)) .. char(0x80 + (n % 0x40))
- else -- wrong:
- -- return char(0xF1 + floor(n/0x1000000)) .. char(0x80 + floor(n/0x40000)) .. char(0x80 + floor(n/0x1000)) .. char(0x80 + (floor(n/0x40) % 0x40)) .. char(0x80 + (n % 0x40))
- return "?"
- end
- end
-
-end
-
-utf = utf or unicode.utf8
-
-local concat, utfchar, utfgsub = table.concat, utf.char, utf.gsub
-local char, byte, find, bytepairs = string.char, string.byte, string.find, string.bytepairs
-
--- 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'
-}
-
--- \000 fails in <= 5.0 but is valid in >=5.1 where %z is depricated
-
-function unicode.utftype(f)
- local str = f:read(4)
- if not str then
- f:seek('set')
- return 0
- -- elseif find(str,"^%z%z\254\255") then -- depricated
- -- elseif find(str,"^\000\000\254\255") then -- not permitted and bugged
- elseif find(str,"\000\000\254\255",1,true) then -- seems to work okay (TH)
- return 4
- -- elseif find(str,"^\255\254%z%z") then -- depricated
- -- elseif find(str,"^\255\254\000\000") then -- not permitted and bugged
- elseif find(str,"\255\254\000\000",1,true) then -- seems to work okay (TH)
- 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.mkiv",
- 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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- hm, quite unreadable
-
-local gsub = string.gsub
-local concat = table.concat
-local type, next = type, next
-
-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 = gsub(data,"%-%-~[^\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 (gsub(data,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 = gsub(data,"%-%-~[^\n]*\n","")
---~ data = 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 i=1,#libs do
- local lib = libs[i]
- for j=1,#list do
- local pth = gsub(list[j],"\\","/") -- 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 i=1,#libs do
- local lib = libs[i]
- 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",concat(right," "))
- end
- if #wrong > 0 then
- utils.report("skipped libraries: %s",concat(wrong," "))
- end
- else
- utils.report("no valid library path found")
- end
- return 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 ['l-aux'] = {
- version = 1.001,
- comment = "companion to luat-lib.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- for inline, no store split : for s in string.gmatch(str,",* *([^,]+)") do .. end
-
-aux = aux or { }
-
-local concat, format, gmatch = table.concat, string.format, string.gmatch
-local tostring, type = tostring, type
-local lpegmatch = lpeg.match
-
-local P, R, V = lpeg.P, lpeg.R, lpeg.V
-
-local escape, left, right = P("\\"), P('{'), P('}')
-
-lpeg.patterns.balanced = P {
- [1] = ((escape * (left+right)) + (1 - (left+right)) + V(2))^0,
- [2] = left * V(1) * right
-}
-
-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 value = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0)
-
-local key = lpeg.C((1-equal-comma)^1)
-local pattern_a = (space+comma)^0 * (key * equal * value + key * lpeg.C(""))
-local pattern_c = (space+comma)^0 * (key * equal * value)
-
-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
-local pattern_c_s = (pattern_c/set)^1
-
-aux.settings_to_hash_pattern_a = pattern_a_s
-aux.settings_to_hash_pattern_b = pattern_b_s
-aux.settings_to_hash_pattern_c = pattern_c_s
-
-function aux.make_settings_to_hash_pattern(set,how)
- if how == "strict" then
- return (pattern_c/set)^1
- elseif how == "tolerant" then
- return (pattern_b/set)^1
- else
- return (pattern_a/set)^1
- end
-end
-
-function aux.settings_to_hash(str,existing)
- if str and str ~= "" then
- hash = existing or { }
- if moretolerant then
- lpegmatch(pattern_b_s,str)
- else
- lpegmatch(pattern_a_s,str)
- end
- return hash
- else
- return { }
- end
-end
-
-function aux.settings_to_hash_tolerant(str,existing)
- if str and str ~= "" then
- hash = existing or { }
- lpegmatch(pattern_b_s,str)
- return hash
- else
- return { }
- end
-end
-
-function aux.settings_to_hash_strict(str,existing)
- if str and str ~= "" then
- hash = existing or { }
- lpegmatch(pattern_c_s,str)
- return next(hash) and hash
- else
- return nil
- end
-end
-
-local separator = 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*(separator*value)^0)
-
--- "aap, {noot}, mies" : outer {} removes, leading spaces ignored
-
-aux.settings_to_array_pattern = pattern
-
--- we could use a weak table as cache
-
-function aux.settings_to_array(str)
- if not str or str == "" then
- return { }
- else
- return lpegmatch(pattern,str)
- end
-end
-
-local function set(t,v)
- t[#t+1] = v
-end
-
-local value = lpeg.P(lpeg.Carg(1)*value) / set
-local pattern = value*(separator*value)^0 * lpeg.Carg(1)
-
-function aux.add_settings_to_array(t,str)
- return lpegmatch(pattern,str,nil,t)
-end
-
-function aux.hash_to_string(h,separator,yes,no,strict,omit)
- if h then
- local t, s = { }, table.sortedkeys(h)
- omit = omit and table.tohash(omit)
- for i=1,#s do
- local key = s[i]
- if not omit or not omit[key] then
- local value = h[key]
- if type(value) == "boolean" then
- if yes and no then
- if value then
- t[#t+1] = key .. '=' .. yes
- elseif not strict then
- t[#t+1] = key .. '=' .. no
- end
- elseif value or not strict then
- t[#t+1] = key .. '=' .. tostring(value)
- end
- else
- t[#t+1] = key .. '=' .. value
- end
- end
- end
- return concat(t,separator or ",")
- else
- return ""
- end
-end
-
-function aux.array_to_string(a,separator)
- if a then
- return concat(a,separator or ",")
- else
- return ""
- end
-end
-
-function aux.settings_to_set(str,t)
- t = t or { }
- for s in gmatch(str,"%s*([^,]+)") do
- t[s] = true
- end
- return t
-end
-
-local value = lbrace * lpeg.C((nobrace + nested)^0) * rbrace
-local pattern = lpeg.Ct((space + value)^0)
-
-function aux.arguments_to_table(str)
- return lpegmatch(pattern,str)
-end
-
--- temporary here
-
-function aux.getparameters(self,class,parentclass,settings)
- local sc = self[class]
- if not sc then
- sc = table.clone(self[parent])
- self[class] = sc
- end
- aux.settings_to_hash(settings,sc)
-end
-
--- temporary here
-
-local digit = lpeg.R("09")
-local period = lpeg.P(".")
-local zero = lpeg.P("0")
-local trailingzeros = zero^0 * -digit -- suggested by Roberto R
-local case_1 = period * trailingzeros / ""
-local case_2 = period * (digit - trailingzeros)^1 * (trailingzeros / "")
-local number = digit^1 * (case_1 + case_2)
-local stripper = lpeg.Cs((number + 1)^0)
-
---~ local sample = "bla 11.00 bla 11 bla 0.1100 bla 1.00100 bla 0.00 bla 0.001 bla 1.1100 bla 0.100100100 bla 0.00100100100"
---~ collectgarbage("collect")
---~ str = string.rep(sample,10000)
---~ local ts = os.clock()
---~ lpegmatch(stripper,str)
---~ print(#str, os.clock()-ts, lpegmatch(stripper,sample))
-
-lpeg.patterns.strip_zeros = stripper
-
-function aux.strip_zeros(str)
- return lpegmatch(stripper,str)
-end
-
-function aux.definetable(target) -- defines undefined tables
- local composed, t = nil, { }
- for name in gmatch(target,"([^%.]+)") do
- if composed then
- composed = composed .. "." .. name
- else
- composed = name
- end
- t[#t+1] = format("%s = %s or { }",composed,composed)
- end
- return concat(t,"\n")
-end
-
-function aux.accesstable(target)
- local t = _G
- for name in gmatch(target,"([^%.]+)") do
- t = t[name]
- end
- return t
-end
-
--- as we use this a lot ...
-
---~ function aux.cachefunction(action,weak)
---~ local cache = { }
---~ if weak then
---~ setmetatable(cache, { __mode = "kv" } )
---~ end
---~ local function reminder(str)
---~ local found = cache[str]
---~ if not found then
---~ found = action(str)
---~ cache[str] = found
---~ end
---~ return found
---~ end
---~ return reminder, cache
---~ end
-
-
-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 trac-tra.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- the <anonymous> tag is kind of generic and used for functions that are not
--- bound to a variable, like node.new, node.copy etc (contrary to for instance
--- node.has_attribute which is bound to a has_attribute local variable in mkiv)
-
-local debug = require "debug"
-
-local getinfo = debug.getinfo
-local type, next = type, next
-local concat = table.concat
-local format, find, lower, gmatch, gsub = string.format, string.find, string.lower, string.gmatch, string.gsub
-
-debugger = debugger or { }
-
-local counters = { }
-local names = { }
-
--- one
-
-local function hook()
- local f = getinfo(2,"f").func
- local n = getinfo(2,"Sn")
--- if n.what == "C" and n.name then print (n.namewhat .. ': ' .. n.name) end
- if f then
- local cf = counters[f]
- if cf == nil then
- counters[f] = 1
- names[f] = n
- else
- counters[f] = cf + 1
- end
- end
-end
-local function getname(func)
- local n = names[func]
- if n then
- if n.what == "C" then
- return n.name or '<anonymous>'
- else
- -- source short_src linedefined what name namewhat nups func
- local name = n.name or n.namewhat or n.what
- if not name or name == "" then name = "?" end
- return format("%s : %s : %s", n.short_src or "unknown source", n.linedefined or "--", name)
- end
- else
- return "unknown"
- end
-end
-function debugger.showstats(printer,threshold)
- printer = printer or texio.write or print
- threshold = threshold or 0
- local total, grandtotal, functions = 0, 0, 0
- printer("\n") -- ugly but ok
- -- table.sort(counters)
- for func, count in next, counters do
- if count > threshold then
- local name = getname(func)
- if not find(name,"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 next, 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)
-
-setters = setters or { }
-setters.data = setters.data or { }
-
---~ local function set(t,what,value)
---~ local data, done = t.data, t.done
---~ if type(what) == "string" then
---~ what = aux.settings_to_array(what) -- inefficient but ok
---~ end
---~ for i=1,#what do
---~ local w = what[i]
---~ 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 set(t,what,value)
- local data, done = t.data, t.done
- if type(what) == "string" then
- what = aux.settings_to_hash(what) -- inefficient but ok
- end
- for w, v in next, what do
- if v == "" then
- v = value
- else
- v = toboolean(v)
- end
- 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](v)
- end
- end
- end
- end
-end
-
-local function reset(t)
- for d, f in next, t.data do
- for i=1,#f do
- f[i](false)
- end
- end
-end
-
-local function enable(t,what)
- set(t,what,true)
-end
-
-local function disable(t,what)
- local data = t.data
- if not what or what == "" then
- t.done = { }
- reset(t)
- else
- set(t,what,false)
- end
-end
-
-function setters.register(t,what,...)
- local data = t.data
- 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(t,fnc,value,nesting) end
- end
- end
-end
-
-function setters.enable(t,what)
- local e = t.enable
- t.enable, t.done = enable, { }
- enable(t,string.simpleesc(tostring(what)))
- t.enable, t.done = e, { }
-end
-
-function setters.disable(t,what)
- local e = t.disable
- t.disable, t.done = disable, { }
- disable(t,string.simpleesc(tostring(what)))
- t.disable, t.done = e, { }
-end
-
-function setters.reset(t)
- t.done = { }
- reset(t)
-end
-
-function setters.list(t) -- pattern
- local list = table.sortedkeys(t.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
-
-function setters.show(t)
- commands.writestatus("","")
- local list = setters.list(t)
- for k=1,#list do
- commands.writestatus(t.name,list[k])
- end
- commands.writestatus("","")
-end
-
--- we could have used a bit of oo and the trackers:enable syntax but
--- there is already a lot of code around using the singular tracker
-
--- we could make this into a module
-
-function setters.new(name)
- local t
- t = {
- data = { },
- name = name,
- enable = function(...) setters.enable (t,...) end,
- disable = function(...) setters.disable (t,...) end,
- register = function(...) setters.register(t,...) end,
- list = function(...) setters.list (t,...) end,
- show = function(...) setters.show (t,...) end,
- }
- setters.data[name] = t
- return t
-end
-
-trackers = setters.new("trackers")
-directives = setters.new("directives")
-experiments = setters.new("experiments")
-
--- nice trick: we overload two of the directives related functions with variants that
--- do tracing (itself using a tracker) .. proof of concept
-
-local trace_directives = false local trace_directives = false trackers.register("system.directives", function(v) trace_directives = v end)
-local trace_experiments = false local trace_experiments = false trackers.register("system.experiments", function(v) trace_experiments = v end)
-
-local e = directives.enable
-local d = directives.disable
-
-function directives.enable(...)
- commands.writestatus("directives","enabling: %s",concat({...}," "))
- e(...)
-end
-
-function directives.disable(...)
- commands.writestatus("directives","disabling: %s",concat({...}," "))
- d(...)
-end
-
-local e = experiments.enable
-local d = experiments.disable
-
-function experiments.enable(...)
- commands.writestatus("experiments","enabling: %s",concat({...}," "))
- e(...)
-end
-
-function experiments.disable(...)
- commands.writestatus("experiments","disabling: %s",concat({...}," "))
- d(...)
-end
-
--- a useful example
-
-directives.register("system.nostatistics", function(v)
- statistics.enable = not v
-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.mkiv",
- 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_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end)
-
-local format, sub, match, gsub, find = string.format, string.sub, string.match, string.gsub, string.find
-local unquote, quote = string.unquote, string.quote
-
--- 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=1,#arg do
- local argument = arg[index]
- if index > 0 then
- local flag, value = match(argument,"^%-+(.-)=(.-)$")
- if flag then
- arguments[flag] = unquote(value or "")
- else
- flag = match(argument,"^%-+(.+)")
- 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 = table.sortedkeys(arguments)
- for k=1,#sortedflags do
- sortedflags[k] = "^" .. sortedflags[k]
- end
- environment.sortedflags = sortedflags
- end
- -- example of potential clash: ^mode ^modefile
- for k=1,#sortedflags do
- local v = sortedflags[k]
- if find(name,v) then
- return arguments[sub(v,2,#v)]
- end
- end
- end
- return nil
-end
-
-environment.argument("x",true)
-
-function environment.split_arguments(separator) -- rather special, cut-off before separator
- local done, before, after = false, { }, { }
- local original_arguments = environment.original_arguments
- for k=1,#original_arguments do
- local v = original_arguments[k]
- 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 = unquote(a)
- return a
- elseif #arg > 0 then
- local result = { }
- for i=1,#arg do
- local a = arg[i]
- a = resolvers.resolve(a)
- a = unquote(a)
- a = gsub(a,'"','\\"') -- tricky
- if find(a," ") then
- result[#result+1] = quote(a)
- 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 remove the " then and add them later)
- local newarg, instring = { }, false
-
- for index=1,#arg do
- local argument = arg[index]
- if find(argument,"^\"") then
- newarg[#newarg+1] = gsub(argument,"^\"","")
- if not find(argument,"\"$") then
- instring = true
- end
- elseif find(argument,"\"$") then
- newarg[#newarg] = newarg[#newarg] .. " " .. gsub(argument,"\"$","")
- 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_locating then
- logs.report("fileio","loading file %s", fullname)
- end
- return environment.loadedluacode(fullname)
- else
- if trace_locating 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_locating 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_locating 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_locating 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 trace_locating 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 trac-inf.mkiv",
- 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
-
-local notimer
-
-function statistics.hastimer(instance)
- return instance and instance.starttime
-end
-
-function statistics.resettiming(instance)
- if not instance then
- notimer = { timing = 0, loadtime = 0 }
- else
- instance.timing, instance.loadtime = 0, 0
- end
-end
-
-function statistics.starttiming(instance)
- if not instance then
- notimer = { }
- instance = notimer
- end
- 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
- else
---~ logs.report("system","nested timing (%s)",tostring(instance))
- end
- instance.timing = it + 1
-end
-
-function statistics.stoptiming(instance, report)
- if not instance then
- instance = notimer
- end
- 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)
- if not instance then
- instance = notimer
- end
- return format("%0.3f",(instance and instance.loadtime) or 0)
-end
-
-function statistics.elapsedindeed(instance)
- if not instance then
- instance = notimer
- end
- local t = (instance and instance.loadtime) or 0
- return t > statistics.threshold
-end
-
-function statistics.elapsedseconds(instance,rest) -- returns nil if 0 seconds
- if statistics.elapsedindeed(instance) then
- return format("%s seconds %s", statistics.elapsedtime(instance),rest or "")
- end
-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
- texio.write_nl("") -- final newline
- 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
-
--- where, not really the best spot for this:
-
-commands = commands or { }
-
-local timer
-
-function commands.resettimer()
- statistics.resettiming(timer)
- statistics.starttiming(timer)
-end
-
-function commands.elapsedtime()
- statistics.stoptiming(timer)
- tex.sprint(statistics.elapsedtime(timer))
-end
-
-commands.resettimer()
-
-
-end -- of closure
-
-do -- create closure to overcome 200 locals limit
-
-if not modules then modules = { } end modules ['trac-log'] = {
- version = 1.001,
- comment = "companion to trac-log.mkiv",
- 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
-
---~ io.stdout:setvbuf("no")
---~ io.stderr:setvbuf("no")
-
-local write_nl, write = texio.write_nl or print, texio.write or io.write
-local format, gmatch = string.format, string.gmatch
-local texcount = tex and tex.count
-
-if texlua then
- write_nl = print
- write = io.write
-end
-
---[[ldx--
-<p>This is a prelude to a more extensive logging module. For the sake
-of parsing log files, in addition to the standard logging we will
-provide an <l n='xml'/> structured file. Actually, any logging that
-is hooked into callbacks will be \XML\ by default.</p>
---ldx]]--
-
-logs = logs or { }
-logs.xml = logs.xml or { }
-logs.tex = logs.tex or { }
-
---[[ldx--
-<p>This looks pretty ugly but we need to speed things up a bit.</p>
---ldx]]--
-
-logs.moreinfo = [[
-more information about ConTeXt and the tools that come with it can be found at:
-
-maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
-webpage : http://www.pragma-ade.nl / http://tex.aanhet.net
-wiki : http://contextgarden.net
-]]
-
-logs.levels = {
- ['error'] = 1,
- ['warning'] = 2,
- ['info'] = 3,
- ['debug'] = 4,
-}
-
-logs.functions = {
- 'report', 'start', 'stop', 'push', 'pop', 'line', 'direct',
- 'start_run', 'stop_run',
- 'start_page_number', 'stop_page_number',
- 'report_output_pages', 'report_output_log',
- 'report_tex_stat', 'report_job_stat',
- 'show_open', 'show_close', 'show_load',
-}
-
-logs.tracers = {
-}
-
-logs.level = 0
-logs.mode = string.lower((os.getenv("MTX.LOG.MODE") or os.getenv("MTX_LOG_MODE") or "tex"))
-
-function logs.set_level(level)
- logs.level = logs.levels[level] or level
-end
-
-function logs.set_method(method)
- for _, v in next, logs.functions do
- logs[v] = logs[method][v] or function() end
- end
-end
-
--- tex logging
-
-function logs.tex.report(category,fmt,...) -- new
- if fmt then
- write_nl(category .. " | " .. format(fmt,...))
- else
- write_nl(category .. " |")
- end
-end
-
-function logs.tex.line(fmt,...) -- new
- if fmt then
- write_nl(format(fmt,...))
- else
- write_nl("")
- end
-end
-
---~ function logs.tex.start_page_number()
---~ local real, user, sub = texcount.realpageno, texcount.userpageno, texcount.subpageno
---~ 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
-
-local real, user, sub
-
-function logs.tex.start_page_number()
- real, user, sub = texcount.realpageno, texcount.userpageno, texcount.subpageno
-end
-
-function logs.tex.stop_page_number()
- if real > 0 then
- if user > 0 then
- if sub > 0 then
- logs.report("pages", "flushing realpage %s, userpage %s, subpage %s",real,user,sub)
- else
- logs.report("pages", "flushing realpage %s, userpage %s",real,user)
- end
- else
- logs.report("pages", "flushing realpage %s",real)
- end
- else
- logs.report("pages", "flushing page")
- end
- io.flush()
-end
-
-logs.tex.report_job_stat = statistics.show_job_stat
-
--- xml logging
-
-function logs.xml.report(category,fmt,...) -- new
- if fmt then
- write_nl(format("<r category='%s'>%s</r>",category,format(fmt,...)))
- else
- write_nl(format("<r category='%s'/>",category))
- end
-end
-function logs.xml.line(fmt,...) -- new
- if fmt then
- write_nl(format("<r>%s</r>",format(fmt,...)))
- else
- write_nl("<r/>")
- end
-end
-
-function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end
-function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end
-function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end
-function logs.xml.pop () if logs.level > 0 then tw(" -->" ) end end
-
-function logs.xml.start_run()
- write_nl("<?xml version='1.0' standalone='yes'?>")
- write_nl("<job>") -- xmlns='www.pragma-ade.com/luatex/schemas/context-job.rng'
- write_nl("")
-end
-
-function logs.xml.stop_run()
- write_nl("</job>")
-end
-
-function logs.xml.start_page_number()
- write_nl(format("<p real='%s' page='%s' sub='%s'", texcount.realpageno, texcount.userpageno, texcount.subpageno))
-end
-
-function logs.xml.stop_page_number()
- write("/>")
- write_nl("")
-end
-
-function logs.xml.report_output_pages(p,b)
- write_nl(format("<v k='pages' v='%s'/>", p))
- write_nl(format("<v k='bytes' v='%s'/>", b))
- write_nl("")
-end
-
-function logs.xml.report_output_log()
-end
-
-function logs.xml.report_tex_stat(k,v)
- texiowrite_nl("log","<v k='"..k.."'>"..tostring(v).."</v>")
-end
-
-local level = 0
-
-function logs.xml.show_open(name)
- level = level + 1
- texiowrite_nl(format("<f l='%s' n='%s'>",level,name))
-end
-
-function logs.xml.show_close(name)
- texiowrite("</f> ")
- level = level - 1
-end
-
-function logs.xml.show_load(name)
- texiowrite_nl(format("<f l='%s' n='%s'/>",level+1,name))
-end
-
---
-
-local name, banner = 'report', 'context'
-
-local function report(category,fmt,...)
- if fmt then
- write_nl(format("%s | %s: %s",name,category,format(fmt,...)))
- elseif category then
- write_nl(format("%s | %s",name,category))
- else
- write_nl(format("%s |",name))
- end
-end
-
-local function simple(fmt,...)
- if fmt then
- write_nl(format("%s | %s",name,format(fmt,...)))
- else
- write_nl(format("%s |",name))
- end
-end
-
-function logs.setprogram(_name_,_banner_,_verbose_)
- name, banner = _name_, _banner_
- if _verbose_ then
- trackers.enable("resolvers.locating")
- 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.locating")
- else
- trackers.disable("resolvers.locating")
- end
- logs.verbose = what or false
-end
-
-function logs.extendbanner(_banner_,_verbose_)
- banner = banner .. " | ".. _banner_
- if _verbose_ ~= nil then
- logs.setverbose(what)
- end
-end
-
-logs.verbose = false
-logs.report = logs.tex.report
-logs.simple = logs.tex.report
-
-function logs.reportlines(str) -- todo: <lines></lines>
- for line in gmatch(str,"(.-)[\n\r]") do
- logs.report(line)
- end
-end
-
-function logs.reportline() -- for scripts too
- logs.report()
-end
-
-logs.simpleline = logs.reportline
-
-function logs.reportbanner() -- for scripts too
- logs.report(banner)
-end
-
-function logs.help(message,option)
- logs.reportbanner()
- 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
-
-function logs.fatal(where,...)
- logs.report(where,"fatal error: %s, aborting now",format(...))
- os.exit()
-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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files",
-}
-
--- 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]
--- 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 lpegmatch = lpeg.match
-
-local trace_locating, trace_detail, trace_expansions = false, false, false
-
-trackers.register("resolvers.locating", function(v) trace_locating = v end)
-trackers.register("resolvers.details", function(v) trace_detail = v end)
-trackers.register("resolvers.expansions", function(v) trace_expansions = v end) -- todo
-
-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.type == "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', 'dfont' }
-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 maps'] = 'cid' -- great, why no cid files
-alternatives['font feature files'] = 'fea' -- and fea files here
-alternatives['opentype fonts'] = 'otf'
-alternatives['truetype fonts'] = 'ttf'
-alternatives['truetype collections'] = 'ttc'
-alternatives['truetype dictionary'] = 'dfont'
-alternatives['type1 fonts'] = 'pfb'
-
--- obscure ones
-
-formats ['misc fonts'] = ''
-suffixes['misc fonts'] = { }
-
-formats ['sfd'] = 'SFDFONTS'
-suffixes ['sfd'] = { 'sfd' }
-alternatives['subfont definition files'] = 'sfd'
-
--- lib paths
-
-formats ['lib'] = 'CLUAINPUTS' -- new (needs checking)
-suffixes['lib'] = (os.libsuffix and { os.libsuffix }) or { 'dll', 'so' }
-
--- 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, iv = instance.environment, instance.variables
- local function fix(varname,default)
- local proname = varname .. "." .. instance.progname or "crap"
- local p, v = ie[proname], ie[varname] or iv[varname]
- if not ((p and p ~= "") or (v and v ~= "")) then
- iv[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
- -- this will go away some day
- fix("FONTFEATURES", ".;$TEXMF/fonts/{data,fea}//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
- fix("FONTCIDMAPS" , ".;$TEXMF/fonts/{data,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_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 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
-
-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
- if trace_expansions then
- logs.report("fileio","expanding variable '%s'",str)
- end
- t = t or { }
- str = gsub(str,",}",",@}")
- str = gsub(str,"{,","{@,")
- -- str = "@" .. str .. "@"
- local ok, done
- 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
- if trace_expansions then
- for k=1,#t do
- logs.report("fileio","% 4i: %s",k,t[k])
- 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)
-
-local args = environment and environment.original_arguments or arg -- this needs a cleanup
-
-resolvers.ownbin = resolvers.ownbin or args[-2] or arg[-2] or args[-1] or arg[-1] or arg[0] or "luatex"
-resolvers.ownbin = gsub(resolvers.ownbin,"\\","/")
-
-function resolvers.getownpath()
- local ownpath = resolvers.ownpath or os.selfdir
- if not ownpath or ownpath == "" or ownpath == "unset" then
- ownpath = args[-1] or arg[-1]
- ownpath = ownpath and file.dirname(gsub(ownpath,"\\","/"))
- if not ownpath or ownpath == "" then
- ownpath = args[-0] or arg[-0]
- ownpath = ownpath and file.dirname(gsub(ownpath,"\\","/"))
- end
- local binary = resolvers.ownbin
- if not ownpath or ownpath == "" then
- ownpath = ownpath and file.dirname(binary)
- end
- if not ownpath or ownpath == "" then
- if os.binsuffix ~= "" then
- binary = file.replacesuffix(binary,os.binsuffix)
- 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_locating and p ~= pp then
- logs.report("fileio","following symlink '%s' to '%s'",p,pp)
- end
- ownpath = pp
- lfs.chdir(olddir)
- else
- if trace_locating then
- logs.report("fileio","unable to check path '%s'",p)
- end
- ownpath = p
- end
- break
- end
- end
- end
- if not ownpath or ownpath == "" then
- ownpath = "."
- logs.report("fileio","forcing fallback ownpath .")
- elseif trace_locating then
- logs.report("fileio","using ownpath '%s'",ownpath)
- end
- end
- resolvers.ownpath = ownpath
- function resolvers.getownpath()
- return resolvers.ownpath
- end
- return ownpath
-end
-
-local own_places = { "SELFAUTOLOC", "SELFAUTODIR", "SELFAUTOPARENT", "TEXMFCNF" }
-
-local function identify_own()
- local ownpath = resolvers.getownpath() or dir.current()
- 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_locating 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')
- if lfs.isfile(lname) then
- local dname = file.dirname(fname) -- 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_locating then
- logs.report("fileio","loading configuration file %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_locating then
- logs.report("fileio","skipping configuration file '%s'", fname)
- end
- end
-end
-
-local function collapse_cnf_data() -- potential optimization: pass start index (setup and configuration are shared)
- local order = instance.order
- for i=1,#order do
- local c = order[i]
- 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()
- local cnffiles = instance.cnffiles
- for i=1,#cnffiles do
- load_cnf_file(cnffiles[i])
- end
- end
- -- instance.cnffiles contain complete names now !
- -- we still use a funny mix of cnf and new but soon
- -- we will switch to lua exclusively as we only use
- -- the file to collect the tree roots
- if #instance.cnffiles == 0 then
- if trace_locating then
- logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)")
- end
- else
- local cnffiles = instance.cnffiles
- instance.rootpath = cnffiles[1]
- for k=1,#cnffiles do
- instance.cnffiles[k] = file.collapse_path(cnffiles[k])
- 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]
- local luafiles = instance.luafiles
- for k=1,#luafiles do
- instance.luafiles[k] = file.collapse_path(luafiles[k])
- 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 '%s' appended",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 '%s' prepended",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()
- local texmfpaths = resolvers.clean_path_list('TEXMF')
- for i=1,#texmfpaths do
- local path = texmfpaths[i]
- if trace_locating 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 '%s' found",specification)
- end
- resolvers.append_hash('file',specification,filename)
- elseif trace_locating then
- logs.report("fileio","tex locator '%s' not found",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
- local hashes = instance.hashes
- for k=1,#hashes do
- local hash = hashes[k]
- 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()
- local hashes = instance.hashes
- for i=1,#hashes do
- resolvers.generatedatabase(hashes[i].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"))
-
---~ local l_forbidden = lpeg.S("~`!#$%^&*()={}[]:;\"\'||\\/<>,?\n\r\t")
---~ local l_confusing = lpeg.P(" ")
---~ local l_character = lpeg.patterns.utf8
---~ local l_dangerous = lpeg.P(".")
-
---~ local l_normal = (l_character - l_forbidden - l_confusing - l_dangerous) * (l_character - l_forbidden - l_confusing^2)^0 * lpeg.P(-1)
---~ ----- l_normal = l_normal * lpeg.Cc(true) + lpeg.Cc(false)
-
---~ local function test(str)
---~ print(str,lpeg.match(l_normal,str))
---~ end
---~ test("ヒラギノ明朝 Pro W3")
---~ test("..ヒラギノ明朝 Pro W3")
---~ test(":ヒラギノ明朝 Pro W3;")
---~ test("ヒラギノ明朝 /Pro W3;")
---~ test("ヒラギノ明朝 Pro W3")
-
-function resolvers.generators.tex(specification)
- local tag = specification
- if trace_locating 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 lpegmatch(weird,name) then
- -- if lpegmatch(l_normal,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_locating 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.
-
---~ local checkedsplit = string.checkedsplit
-
-local cache = { }
-
-local splitter = lpeg.Ct(lpeg.splitat(lpeg.S(os.type == "windows" and ";" or ":;")))
-
-local function split_kpse_path(str) -- beware, this can be either a path or a {specification}
- local found = cache[str]
- if not found then
- if str == "" then
- found = { }
- else
- str = gsub(str,"\\","/")
---~ local split = (find(str,";") and checkedsplit(str,";")) or checkedsplit(str,io.pathseparator)
-local split = lpegmatch(splitter,str)
- found = { }
- for i=1,#split do
- local s = split[i]
- if not find(s,"^{*unset}*") then
- found[#found+1] = s
- end
- end
- if trace_expansions then
- logs.report("fileio","splitting path specification '%s'",str)
- for k=1,#found do
- logs.report("fileio","% 4i: %s",k,found[k])
- end
- end
- cache[str] = found
- end
- end
- return found
-end
-
-resolvers.split_kpse_path = split_kpse_path
-
-function resolvers.splitconfig()
- for i=1,#instance do
- local c = instance[i]
- for k,v in next, c do
- if type(v) == 'string' then
- local t = split_kpse_path(v)
- if #t > 1 then
- c[k] = t
- end
- end
- end
- end
-end
-
-function resolvers.joinconfig()
- local order = instance.order
- for i=1,#order do
- local c = order[i]
- for k,v in next, c do -- indexed?
- 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 split_kpse_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, p = { }, { }, split_kpse_path(v)
- for kk=1,#p do
- local vv = p[kk]
- 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
- local sortedfiles = sortedkeys(files)
- for i=1,#sortedfiles do
- local k = sortedfiles[i]
- local fk = files[k]
- if type(fk) == 'table' then
- t[#t+1] = "\t['" .. k .. "']={"
- local sortedfk = sortedkeys(fk)
- for j=1,#sortedfk do
- local kk = sortedfk[j]
- 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
-
-local data_state = { }
-
-function resolvers.data_state()
- return data_state or { }
-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_locating 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,
- uuid = os.uuid(),
- }
- local ok = io.savedata(luaname,resolvers.serialize(data))
- if ok then
- if trace_locating 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_locating then
- logs.report("fileio","'%s' compiled to '%s'",dataname,lucname)
- end
- else
- if trace_locating then
- logs.report("fileio","compiling failed for '%s', deleting file '%s'",dataname,lucname)
- end
- os.remove(lucname)
- end
- elseif trace_locating 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
- data_state[#data_state+1] = data.uuid
- if trace_locating then
- logs.report("fileio","loading '%s' for '%s' from '%s'",dataname,pathname,filename)
- end
- instance[dataname][pathname] = data.content
- else
- if trace_locating then
- logs.report("fileio","skipping '%s' for '%s' from '%s'",dataname,pathname,filename)
- end
- instance[dataname][pathname] = { }
- instance.loaderror = true
- end
- elseif trace_locating 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()
- local luafiles = instance.luafiles
- for i=1,#luafiles do
- local cnf = luafiles[i]
- 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_locating 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_locating then
- logs.report("fileio","skipping configuration file '%s'",filename)
- end
- instance['setup'][pathname] = { }
- instance.loaderror = true
- end
- elseif trace_locating 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
- local cnffiles = instance.cnffiles
- for i=1,#cnffiles do
- local cnf = cnffiles[i]
- 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 { } -- ep ?
- 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(tmp)
- else
- return resolvers.expanded_path_list(str)
- 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","file '%s' is readable",name)
- else
- logs.report("fileio","file '%s' is not readable", 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","checking name '%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","deep checking '%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","no match in '%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)
- -- 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","remembering file '%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","file '%s' found directly",filename)
- end
- instance.found[stamp] = { filename }
- return { filename }
- end
- end
- if find(filename,'%*') then
- if trace_locating then
- logs.report("fileio","checking 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 name '%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 = gsub(filename .. "$","([%.%-])","%%%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
- --
- if basename ~= filename then
- 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 find(rr,pattern) then
- result[#result+1], ok = rr, true
- end
- 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 find(ff,pattern) then
- -- result[#result+1], ok = ff, true
- -- end
- -- end
- -- end
- end
- if not ok and trace_locating then
- logs.report("fileio","qualified name '%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","checking filename '%s', filetype '%s', wanted files '%s'",filename, filetype or '?',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 dirlist = { }
- if filelist then
- for i=1,#filelist do
- dirlist[i] = file.dirname(filelist[i][2]) .. "/"
- end
- end
- if trace_detail then
- logs.report("fileio","checking filename '%s'",filename)
- end
- -- a bit messy ... esp the doscan setting here
- local doscan
- for k=1,#pathlist do
- local path = pathlist[k]
- if find(path,"^!!") then doscan = false else doscan = true end
- local pathname = gsub(path,"^!+", '')
- done = false
- -- using file list
- if filelist then
- local expression
- -- compare list entries with permitted pattern -- /xx /xx//
- if not find(pathname,"/$") then
- expression = pathname .. "/"
- else
- expression = pathname
- end
- expression = gsub(expression,"([%-%.])","%%%1") -- this also influences
- expression = gsub(expression,"//+$", '/.*') -- later usage of pathname
- expression = gsub(expression,"//", '/.-/') -- not ok for /// but harmless
- expression = "^" .. expression .. "$"
- if trace_detail then
- logs.report("fileio","using pattern '%s' for path '%s'",expression,pathname)
- end
- for k=1,#filelist do
- local fl = filelist[k]
- local f = fl[2]
- local d = dirlist[k]
- if find(d,expression) then
- --- todo, test for readable
- result[#result+1] = fl[3]
- resolvers.register_in_trees(f) -- for tracing used files
- done = true
- if instance.allresults then
- if trace_detail then
- logs.report("fileio","match in hash for file '%s' on path '%s', continue scanning",f,d)
- end
- else
- if trace_detail then
- logs.report("fileio","match in hash for file '%s' on path '%s', quit scanning",f,d)
- end
- break
- end
- elseif trace_detail then
- logs.report("fileio","no match in hash for file '%s' on path '%s'",f,d)
- 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 '%s' by scanning",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] or { }
- 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() -- will become the new method
- resolvers.expand_variables()
- resolvers.load_cnf() -- will be skipped when we have a lua file
- 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_locating then
- logs.report("fileio",str) -- has already verbose
- else
- print(str)
- end
- end
- if trace_locating then
- report('') -- ?
- end
- for f=1,#files do
- local file = files[f]
- local result = command(file,filetype,mustexist)
- if type(result) == 'string' then
- report(result)
- else
- for i=1,#result do
- report(result[i]) -- could be unpack
- 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 next, t do -- indexed?
- s[#s+1] = k .. "=" .. tostring(v)
- end
- return concat(s, sep or " | ")
-end
-
-function resolvers.methodhandler(what, filename, filetype) -- ...
- filename = file.collapse_path(filename)
- 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)
- local pathlist = resolvers.expanded_path_list(name)
- for i=1,#pathlist do
- func("^"..resolvers.clean_path(pathlist[i]))
- end
-end
-
-function resolvers.do_with_var(name,func)
- func(expanded_var(name))
-end
-
-function resolvers.with_files(pattern,handle)
- local hashes = instance.hashes
- for i=1,#hashes do
- local hash = hashes[i]
- 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 next, v do -- indexed
- handle(blobtype,blobpath,vv,k)
- end
- end
- end
- end
- end
- end
- end
-end
-
-function resolvers.locate_format(name)
- local barename, fmtname = gsub(name,"%.%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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
---[[ldx--
-<p>This module deals with caching data. It sets up the paths and
-implements loaders and savers for tables. Best is to set the
-following variable. When not set, the usual paths will be
-checked. Personally I prefer the (users) temporary path.</p>
-
-</code>
-TEXMFCACHE=$TMP;$TEMP;$TMPDIR;$TEMPDIR;$HOME;$TEXMFVAR;$VARTEXMF;.
-</code>
-
-<p>Currently we do no locking when we write files. This is no real
-problem because most caching involves fonts and the chance of them
-being written at the same time is small. We also need to extend
-luatools with a recache feature.</p>
---ldx]]--
-
-local format, lower, gsub = string.format, string.lower, string.gsub
-
-local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end) -- not used yet
-
-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)
- local dirs = { ... }
- if #dirs > 0 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
- loader = loader()
- collectgarbage("step")
- 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
- data.cache_uuid = os.uuid()
- 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.mkiv",
- 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.mkiv",
- 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.mkiv",
- 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)
-
---[[ldx--
-<p>Once we found ourselves defining similar cache constructs
-several times, containers were introduced. Containers are used
-to collect tables in memory and reuse them when possible based
-on (unique) hashes (to be provided by the calling function).</p>
-
-<p>Caching to disk is disabled by default. Version numbers are
-stored in the saved table which makes it possible to change the
-table structures without bothering about the disk cache.</p>
-
-<p>Examples of usage can be found in the font related code.</p>
---ldx]]--
-
-containers = containers or { }
-
-containers.usecache = true
-
-local function report(container,tag,name)
- if trace_cache or trace_containers then
- logs.report(format("%s cache",container.subcategory),"%s: %s",tag,name or 'invalid')
- end
-end
-
-local allocated = { }
-
--- tracing
-
-function containers.define(category, subcategory, version, enabled)
- return function()
- if category and subcategory then
- local c = allocated[category]
- if not c then
- c = { }
- allocated[category] = c
- end
- local s = c[subcategory]
- if not s then
- s = {
- category = category,
- subcategory = subcategory,
- storage = { },
- enabled = enabled,
- version = version or 1.000,
- trace = false,
- path = caches and caches.setpath and caches.setpath(category,subcategory),
- }
- c[subcategory] = s
- end
- return s
- else
- return nil
- end
- end
-end
-
-function containers.is_usable(container, name)
- return container.enabled and caches and caches.iswritable(container.path, name)
-end
-
-function containers.is_valid(container, name)
- if name and name ~= "" then
- local storage = container.storage[name]
- return storage and 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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local format, lower, gsub, find = string.format, string.lower, string.gsub, string.find
-
-local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v 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 (not mountpaths or #mountpaths == 0) and usecache then
- mountpaths = { caches.setpath("mount") }
- end
- if mountpaths and #mountpaths > 0 then
- statistics.starttiming(resolvers.instance)
- for k=1,#mountpaths do
- local root = mountpaths[k]
- local f = io.open(root.."/url.tmi")
- if f then
- for line in f:lines() do
- if line then
- if find(line,"^[%%#%-]") then -- or %W
- -- skip
- elseif find(line,"^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")
- local luvbanner = luv.enginebanner or "?"
- if luvbanner ~= enginebanner then
- return string.format("engine mismatch (luv:%s <> bin:%s)",luvbanner,enginebanner)
- end
- local luvhash = luv.sourcehash or "?"
- if luvhash ~= sourcehash then
- return string.format("source mismatch (luv:%s <> bin:%s)",luvhash,sourcehash)
- end
- else
- return "invalid status file"
- end
- else
- return "missing status file"
- end
- end
- return true
-end
-
-
-end -- of closure
-
-do -- create closure to overcome 200 locals limit
-
-if not modules then modules = { } end modules ['luat-kps'] = {
- version = 1.001,
- comment = "companion to luatools.lua",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
---[[ldx--
-<p>This file is used when we want the input handlers to behave like
-<type>kpsewhich</type>. What to do with the following:</p>
-
-<typing>
-{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c}
-$SELFAUTOLOC : /usr/tex/bin/platform
-$SELFAUTODIR : /usr/tex/bin
-$SELFAUTOPARENT : /usr/tex
-</typing>
-
-<p>How about just forgetting about them?</p>
---ldx]]--
-
-local suffixes = resolvers.suffixes
-local formats = resolvers.formats
-
-suffixes['gf'] = { '<resolution>gf' }
-suffixes['pk'] = { '<resolution>pk' }
-suffixes['base'] = { 'base' }
-suffixes['bib'] = { 'bib' }
-suffixes['bst'] = { 'bst' }
-suffixes['cnf'] = { 'cnf' }
-suffixes['mem'] = { 'mem' }
-suffixes['mf'] = { 'mf' }
-suffixes['mfpool'] = { 'pool' }
-suffixes['mft'] = { 'mft' }
-suffixes['mppool'] = { 'pool' }
-suffixes['graphic/figure'] = { 'eps', 'epsi' }
-suffixes['texpool'] = { 'pool' }
-suffixes['PostScript header'] = { 'pro' }
-suffixes['ist'] = { 'ist' }
-suffixes['web'] = { 'web', 'ch' }
-suffixes['cweb'] = { 'w', 'web', 'ch' }
-suffixes['cmap files'] = { 'cmap' }
-suffixes['lig files'] = { 'lig' }
-suffixes['bitmap font'] = { }
-suffixes['MetaPost support'] = { }
-suffixes['TeX system documentation'] = { }
-suffixes['TeX system sources'] = { }
-suffixes['dvips config'] = { }
-suffixes['type42 fonts'] = { }
-suffixes['web2c files'] = { }
-suffixes['other text files'] = { }
-suffixes['other binary files'] = { }
-suffixes['opentype fonts'] = { 'otf' }
-
-suffixes['fmt'] = { 'fmt' }
-suffixes['texmfscripts'] = { 'rb','lua','py','pl' }
-
-suffixes['pdftex config'] = { }
-suffixes['Troff fonts'] = { }
-
-suffixes['ls-R'] = { }
-
---[[ldx--
-<p>If you wondered abou tsome of the previous mappings, how about
-the next bunch:</p>
---ldx]]--
-
-formats['bib'] = ''
-formats['bst'] = ''
-formats['mft'] = ''
-formats['ist'] = ''
-formats['web'] = ''
-formats['cweb'] = ''
-formats['MetaPost support'] = ''
-formats['TeX system documentation'] = ''
-formats['TeX system sources'] = ''
-formats['Troff fonts'] = ''
-formats['dvips config'] = ''
-formats['graphic/figure'] = ''
-formats['ls-R'] = ''
-formats['other text files'] = ''
-formats['other binary files'] = ''
-
-formats['gf'] = ''
-formats['pk'] = ''
-formats['base'] = 'MFBASES'
-formats['cnf'] = ''
-formats['mem'] = 'MPMEMS'
-formats['mf'] = 'MFINPUTS'
-formats['mfpool'] = 'MFPOOL'
-formats['mppool'] = 'MPPOOL'
-formats['texpool'] = 'TEXPOOL'
-formats['PostScript header'] = 'TEXPSHEADERS'
-formats['cmap files'] = 'CMAPFONTS'
-formats['type42 fonts'] = 'T42FONTS'
-formats['web2c files'] = 'WEB2C'
-formats['pdftex config'] = 'PDFTEXCONFIG'
-formats['texmfscripts'] = 'TEXMFSCRIPTS'
-formats['bitmap font'] = ''
-formats['lig files'] = 'LIGFONTS'
-
-
-end -- of closure
-
-do -- create closure to overcome 200 locals limit
-
-if not modules then modules = { } end modules ['data-aux'] = {
- version = 1.001,
- comment = "companion to luat-lib.mkiv",
- 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_locating = false trackers.register("resolvers.locating", function(v) trace_locating = 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_locating 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_locating 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_locating then
- logs.report("fileio","checking new script %s", newscript)
- end
- if oldscript == newscript then
- if trace_locating then
- logs.report("fileio","old and new script are the same")
- end
- elseif not find(newscript,scriptpath) then
- if trace_locating 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_locating then
- logs.report("fileio","invalid new script name")
- end
- else
- local newdata = io.loaddata(newscript)
- if newdata then
- if trace_locating then
- logs.report("fileio","old script content replaced by new content")
- end
- io.savedata(oldscript,newdata)
- break
- elseif trace_locating 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.mkiv",
- 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
- local sorted = table.sortedkeys(list)
- for i=1,#sorted do
- local key = sorted[i]
- 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
- local sorted = table.sortedkeys(instance.kpsevars)
- for i=1,#sorted do
- local key = sorted[i]
- if not instance.pattern or (instance.pattern=="") or find(key,instance.pattern) then
- report(format("%s\n",key))
- local order = instance.order
- for i=1,#order do
- local str = order[i][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',
- 'l-aux.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.32",environment.arguments["verbose"] or false)
-
-local instance = resolvers.reset()
-
-resolvers.defaultlibs = { -- not all are needed (this will become: context.lus (lua spec)
- '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
-
-local trackspec = environment.argument("trackers") or environment.argument("track")
-
-if trackspec then
- trackers.enable(trackspec)
-end
-
-runners = runners or { }
-messages = messages or { }
-
-messages.no_ini_file = [[
-There is no lua initialization file found. This file can be forced by the
-"--progname" directive, or specified with "--luaname", or it is derived
-automatically from the formatname (aka jobname). It may be that you have
-to regenerate the file database using "luatools --generate".
-]]
-
-messages.help = [[
---generate generate file database
---variables show configuration variables
---expansions show expanded variables
---configurations show configuration order
---expand-braces expand complex variable
---expand-path expand variable (resolve paths)
---expand-var expand variable (resolve references)
---show-path show path expansion of ...
---var-value report value of variable
---find-file report file location
---find-path report path of file
---make or --ini make luatex format
---run or --fmt= run luatex format
---luafile=str lua inifile (default is <progname>.lua)
---lualibs=list libraries to assemble (optional when --compile)
---compile assemble and compile lua inifile
---verbose give a bit more info
---all show all found files
---sort sort cached data
---engine=str target engine
---progname=str format or backend
---pattern=str filter variables
---trackers=list enable given trackers
-]]
-
-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
- local what = { instance.luaname, instance.progname, barename }
- for k=1,#what do
- local v = string.gsub(what[k]..".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 i=1,#mp do
- local name = mp[i]
- 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/lua/luatools.rme b/scripts/context/lua/luatools.rme
deleted file mode 100644
index 901e9a9a3..000000000
--- a/scripts/context/lua/luatools.rme
+++ /dev/null
@@ -1,3 +0,0 @@
-On MSWindows the luatools.lua script is called
-with luatools.exe. On Unix you can either rename
-luatools.lua to luatools, or use a symlink.
diff --git a/scripts/context/lua/mtx-context.lua b/scripts/context/lua/mtx-context.lua
index 36eb01c52..785539754 100644
--- a/scripts/context/lua/mtx-context.lua
+++ b/scripts/context/lua/mtx-context.lua
@@ -765,7 +765,7 @@ function scripts.context.run(ctxdata,filename)
resultname = nil
end
--
- if environment.argument("autopdf") then
+ if environment.argument("autopdf") or environment.argument("closepdf") then
scripts.context.closepdf(filename)
if resultname then
scripts.context.closepdf(resultname)
diff --git a/scripts/context/lua/mtx-update.lua b/scripts/context/lua/mtx-update.lua
index 6552215bb..cd97672bd 100644
--- a/scripts/context/lua/mtx-update.lua
+++ b/scripts/context/lua/mtx-update.lua
@@ -351,6 +351,9 @@ function scripts.update.synchronize()
-- command = format("%s %s %s %s'%s' '%s'", bin, normalflags, deleteflags, url, archives, destination)
-- end
local normalflags, deleteflags = states.get("rsync.flags.normal"), ""
+if os.name == "windows" then
+ normalflags = normalflags .. " -L" -- no symlinks
+end
local dryrunflags = ""
if not environment.argument("force") then
dryrunflags = "--dry-run"
@@ -475,7 +478,7 @@ messages.help = [[
--server=string repository url (rsync://contextgarden.net)
--module=string repository url (minimals)
--repository=string specify version (current, experimental)
---context=string specify version (current, latest, yyyy.mm.dd)
+--context=string specify version (current, latest, beta, yyyy.mm.dd)
--rsync=string rsync binary (rsync)
--texroot=string installation directory (not guessed for the moment)
--engine=string tex engine (luatex, pdftex, xetex)
diff --git a/scripts/context/lua/mtxrun.rme b/scripts/context/lua/mtxrun.rme
deleted file mode 100644
index 9850e389d..000000000
--- a/scripts/context/lua/mtxrun.rme
+++ /dev/null
@@ -1,18 +0,0 @@
-On MSWindows the mtxrun.lua script is called with
-mtxrun.exe. On Unix you can either rename mtxrun.lua
-to mtxrun, or use a symlink.
-
-You can create additional stubs, like
-
-copy mtxrun.exe luatools.exe
-copy mtxrun.exe texexec.exe
-copy mtxrun.exe context.exe
-copy mtxrun.exe mtx-server.exe
-
-The mtxrun.exe program is rather dump and only
-intercepts mtxrun, luatools and texmfstart (for
-old times sake) and passes the buck to mtxrun.lua
-which happens to know enough of mkii to deal
-with kpse based lookups and therefore acts like
-texmfstart but when used with mkiv it behaves
-more clever and looks for more.
diff --git a/scripts/context/stubs/mswin/luatools.lua b/scripts/context/stubs/mswin/luatools.lua
deleted file mode 100644
index 1d87322c1..000000000
--- a/scripts/context/stubs/mswin/luatools.lua
+++ /dev/null
@@ -1,8185 +0,0 @@
-#!/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.mkiv",
- 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, lower = string.sub, string.gsub, string.find, string.match, string.gmatch, string.format, string.char, string.byte, string.rep, string.lower
-local lpegmatch = lpeg.match
-
--- some functions may disappear as they are not used anywhere
-
-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:unquote()
---~ if find(self,"^[\'\"]") then
---~ return sub(self,2,-2)
---~ else
---~ return self
---~ end
---~ end
-
-function string:quote() -- we could use format("%q")
- return format("%q",self)
-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() -- the .- is quite efficient
---~ -- return match(self,"^%s*(.-)%s*$") or ""
---~ -- return match(self,'^%s*(.*%S)') or '' -- posted on lua list
---~ return find(s,'^%s*$') and '' or match(s,'^%s*(.*%S)')
---~ end
-
-do -- roberto's variant:
- local space = lpeg.S(" \t\v\n")
- local nospace = 1 - space
- local stripper = space^0 * lpeg.C((space^0 * nospace^1)^0)
- function string.strip(str)
- return lpegmatch(stripper,str) or ""
- end
-end
-
-function string:is_empty()
- return not find(self,"%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, sub(str,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(sub(str,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 .. rep(chr or " ",m)
- else
- return self
- end
-end
-
-function string:lpadd(n,chr)
- local m = n-#self
- if m > 0 then
- return 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
-
-local simple_escapes = {
- ["-"] = "%-",
- ["."] = "%.",
- ["?"] = ".",
- ["*"] = ".*",
-}
-
-function string:simpleesc()
- return (gsub(self,".",simple_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 lpegmatch(pattern,self)
-end
-
---~ local t = {
---~ "1234567123456712345671234567",
---~ "a\tb\tc",
---~ "aa\tbb\tcc",
---~ "aaa\tbbb\tccc",
---~ "aaaa\tbbbb\tcccc",
---~ "aaaaa\tbbbbb\tccccc",
---~ "aaaaaa\tbbbbbb\tcccccc",
---~ }
---~ for k,v do
---~ print(string.tabtospace(t[k]))
---~ 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
-
-function string:compactlong() -- strips newlines and leading spaces
- self = gsub(self,"[\n\r]+ *","")
- self = gsub(self,"^ *","")
- return self
-end
-
-function string:striplong() -- strips newlines and leading spaces
- self = gsub(self,"^%s*","")
- self = gsub(self,"[\n\r]+ *","\n")
- return self
-end
-
-function string:topattern(lowercase,strict)
- if lowercase then
- self = lower(self)
- end
- self = gsub(self,".",simple_escapes)
- if self == "" then
- self = ".*"
- elseif strict then
- self = "^" .. self .. "$"
- end
- return self
-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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local lpeg = require("lpeg")
-
-lpeg.patterns = lpeg.patterns or { } -- so that we can share
-local patterns = lpeg.patterns
-
-local P, R, S, Ct, C, Cs, Cc, V = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.V
-local match = lpeg.match
-
-local digit, sign = R('09'), S('+-')
-local cr, lf, crlf = P("\r"), P("\n"), P("\r\n")
-local utf8byte = R("\128\191")
-
-patterns.utf8byte = utf8byte
-patterns.utf8one = R("\000\127")
-patterns.utf8two = R("\194\223") * utf8byte
-patterns.utf8three = R("\224\239") * utf8byte * utf8byte
-patterns.utf8four = R("\240\244") * utf8byte * utf8byte * utf8byte
-
-patterns.digit = digit
-patterns.sign = sign
-patterns.cardinal = sign^0 * digit^1
-patterns.integer = sign^0 * digit^1
-patterns.float = sign^0 * digit^0 * P('.') * digit^1
-patterns.number = patterns.float + patterns.integer
-patterns.oct = P("0") * R("07")^1
-patterns.octal = patterns.oct
-patterns.HEX = P("0x") * R("09","AF")^1
-patterns.hex = P("0x") * R("09","af")^1
-patterns.hexadecimal = P("0x") * R("09","AF","af")^1
-patterns.lowercase = R("az")
-patterns.uppercase = R("AZ")
-patterns.letter = patterns.lowercase + patterns.uppercase
-patterns.space = S(" ")
-patterns.eol = S("\n\r")
-patterns.spacer = S(" \t\f\v") -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
-patterns.newline = crlf + cr + lf
-patterns.nonspace = 1 - patterns.space
-patterns.nonspacer = 1 - patterns.spacer
-patterns.whitespace = patterns.eol + patterns.spacer
-patterns.nonwhitespace = 1 - patterns.whitespace
-patterns.utf8 = patterns.utf8one + patterns.utf8two + patterns.utf8three + patterns.utf8four
-patterns.utfbom = P('\000\000\254\255') + P('\255\254\000\000') + P('\255\254') + P('\254\255') + P('\239\187\191')
-
-function lpeg.anywhere(pattern) --slightly adapted from website
- return P { P(pattern) + 1 * V(1) } -- why so complex?
-end
-
-function lpeg.splitter(pattern, action)
- return (((1-P(pattern))^1)/action+1)^0
-end
-
-local spacing = patterns.spacer^0 * patterns.newline -- sort of strip
-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 match(capture,self)
-end
-
-patterns.textline = content
-
---~ local p = lpeg.splitat("->",false) print(match(p,"oeps->what->more")) -- oeps what more
---~ local p = lpeg.splitat("->",true) print(match(p,"oeps->what->more")) -- oeps what->more
---~ local p = lpeg.splitat("->",false) print(match(p,"oeps")) -- oeps
---~ local p = lpeg.splitat("->",true) print(match(p,"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 lpeg.split(separator,str)
- local c = cache[separator]
- if not c then
- c = Ct(splitat(separator))
- cache[separator] = c
- end
- return match(c,str)
-end
-
-function string:split(separator)
- local c = cache[separator]
- if not c then
- c = Ct(splitat(separator))
- cache[separator] = c
- end
- return match(c,self)
-end
-
-lpeg.splitters = cache
-
-local cache = { }
-
-function lpeg.checkedsplit(separator,str)
- local c = cache[separator]
- if not c then
- separator = P(separator)
- local other = C((1 - separator)^0)
- c = Ct(separator^0 * other * (separator^1 * other)^0)
- cache[separator] = c
- end
- return match(c,str)
-end
-
-function string:checkedsplit(separator)
- local c = cache[separator]
- if not c then
- separator = P(separator)
- local other = C((1 - separator)^0)
- c = Ct(separator^0 * other * (separator^1 * other)^0)
- cache[separator] = c
- end
- return match(c,self)
-end
-
---~ function lpeg.append(list,pp)
---~ local p = pp
---~ for l=1,#list do
---~ if p then
---~ p = p + P(list[l])
---~ else
---~ p = P(list[l])
---~ end
---~ end
---~ return p
---~ end
-
---~ from roberto's site:
-
-local f1 = string.byte
-
-local function f2(s) local c1, c2 = f1(s,1,2) return c1 * 64 + c2 - 12416 end
-local function f3(s) local c1, c2, c3 = f1(s,1,3) return (c1 * 64 + c2) * 64 + c3 - 925824 end
-local function f4(s) local c1, c2, c3, c4 = f1(s,1,4) return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168 end
-
-patterns.utf8byte = patterns.utf8one/f1 + patterns.utf8two/f2 + patterns.utf8three/f3 + patterns.utf8four/f4
-
-
-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.mkiv",
- 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, match = string.format, string.find, string.gsub, string.lower, string.dump, string.match
-local getmetatable, setmetatable = getmetatable, setmetatable
-local type, next, tostring, tonumber, ipairs = type, next, tostring, tonumber, ipairs
-local unpack = unpack or table.unpack
-
-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
-
-function table.keys(t)
- local k = { }
- for key, _ in next, t do
- k[#k+1] = key
- end
- return k
-end
-
-local function compare(a,b)
- return (tostring(a) < tostring(b))
-end
-
-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,compare)
- 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.sortedhash(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
-
-table.sortedpairs = table.sortedhash
-
-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) -- obolete, use inline code instead
- return not t or not next(t)
-end
-
-function table.one_entry(t) -- obolete, use inline code instead
- local n = next(t)
- return n and not next(t,n)
-end
-
---~ function table.starts_at(t) -- obsolete, not nice
---~ 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) )
-
--- problem: there no good number_to_string converter with the best resolution
-
-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
- -- we could check for k (index) being number (cardinal)
- if root and next(root) then
- local first, last = nil, 0 -- #root cannot be trusted here (will be ok in 5.2 when ipairs is gone)
- 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)) -- %.99g
- end
- elseif t == "string" then
- if reduce and tonumber(v) 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)) -- %.99g
- --~ 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)) -- %.99g
- 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)) -- %.99g
- end
- else
- if hexify then
- handle(format("%s [%q]=0x%04X,",depth,k,v))
- else
- handle(format("%s [%q]=%s,",depth,k,v)) -- %.99g
- end
- end
- elseif t == "string" then
- if reduce and tonumber(v) 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) -- is this used? meybe a variant with next, ...
- 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
-
--- a better one:
-
-local function flattened(t,f)
- if not f then
- f = { }
- end
- for k, v in next, t do
- if type(v) == "table" then
- flattened(v,f)
- else
- f[k] = v
- end
- end
- return f
-end
-
-table.flattened = flattened
-
--- 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 and b and #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 }) -- why not __index = p ?
- 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.insert_before_value(t,value,extra)
- for i=1,#t do
- if t[i] == extra then
- remove(t,i)
- end
- end
- for i=1,#t do
- if t[i] == value then
- insert(t,i,extra)
- return
- end
- end
- insert(t,1,extra)
-end
-
-function table.insert_after_value(t,value,extra)
- for i=1,#t do
- if t[i] == extra then
- remove(t,i)
- end
- end
- for i=1,#t do
- if t[i] == value then
- insert(t,i+1,extra)
- return
- end
- end
- insert(t,#t+1,extra)
-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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local byte, find, gsub = string.byte, string.find, string.gsub
-
-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
- -- collectgarbage("step") -- sometimes makes a big difference in mem consumption
- 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 or "")
- 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 = gsub(answer,"^%s*(.*)%s*$","%1")
- if answer == "" and default then
- return default
- elseif not options then
- return answer
- else
- for k=1,#options do
- if options[k] == answer then
- return answer
- end
- end
- local pattern = "^" .. answer
- for k=1,#options do
- local v = options[k]
- if find(v,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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local tostring = tostring
-local format, floor, insert, match = string.format, math.floor, table.insert, string.match
-local lpegmatch = lpeg.match
-
-number = number or { }
-
--- a,b,c,d,e,f = number.toset(100101)
-
-function number.toset(n)
- return match(tostring(n),"(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)")
-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 lpegmatch(one,tostring(n))
-end
-
-function number.bits(n,zero)
- local t, i = { }, (zero and 0) or 1
- while n > 0 do
- local m = n % 2
- if m > 0 then
- insert(t,1,i)
- end
- n = floor(n/2)
- i = i + 1
- end
- return t
-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.mkiv",
- 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
-local next, type = next, type
-
-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 next, t do
- if v then
- -- why bother about the leading space
- s = s .. " " .. k
- end
- end
- local n = nums[s]
- if not n then
- n = #tabs + 1
- tabs[n] = t
- nums[s] = n
- end
- return n
- else
- return 0
- end
-end
-
-function set.totable(n)
- if n == 0 then
- return { }
- else
- return tabs[n] or { }
- end
-end
-
-function set.tolist(n)
- if n == 0 or not tabs[n] then
- return ""
- else
- local t = { }
- for k, v in next, tabs[n] do
- if v then
- t[#t+1] = k
- end
- end
- return concat(t," ")
- 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-lib.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- maybe build io.flush in os.execute
-
-local find, format, gsub = string.find, string.format, string.gsub
-local random, ceil = math.random, math.ceil
-
-local execute, spawn, exec, ioflush = os.execute, os.spawn or os.execute, os.exec or os.execute, io.flush
-
-function os.execute(...) ioflush() return execute(...) end
-function os.spawn (...) ioflush() return spawn (...) end
-function os.exec (...) ioflush() return exec (...) end
-
-function os.resultof(command)
- ioflush() -- else messed up logging
- local handle = io.popen(command,"r")
- if not handle then
- -- print("unknown command '".. command .. "' in os.resultof")
- return ""
- else
- return handle:read("*all") or ""
- end
-end
-
---~ os.type : windows | unix (new, we already guessed os.platform)
---~ os.name : windows | msdos | linux | macosx | solaris | .. | generic (new)
---~ os.platform : extended os.name with architecture
-
-if not io.fileseparator then
- if find(os.getenv("PATH"),";") then
- io.fileseparator, io.pathseparator, os.type = "\\", ";", os.type or "mswin"
- else
- io.fileseparator, io.pathseparator, os.type = "/" , ":", os.type or "unix"
- end
-end
-
-os.type = os.type or (io.pathseparator == ";" and "windows") or "unix"
-os.name = os.name or (os.type == "windows" and "mswin" ) or "linux"
-
-if os.type == "windows" then
- os.libsuffix, os.binsuffix = 'dll', 'exe'
-else
- os.libsuffix, os.binsuffix = 'so', ''
-end
-
-function os.launch(str)
- if os.type == "windows" then
- os.execute("start " .. str) -- os.spawn ?
- else
- os.execute(str .. " &") -- os.spawn ?
- 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()))
-
--- no need for function anymore as we have more clever code and helpers now
--- this metatable trickery might as well disappear
-
-os.resolvers = os.resolvers or { }
-
-local resolvers = os.resolvers
-
-local osmt = getmetatable(os) or { __index = function(t,k) t[k] = "unset" return "unset" end } -- maybe nil
-local osix = osmt.__index
-
-osmt.__index = function(t,k)
- return (resolvers[k] or osix)(t,k)
-end
-
-setmetatable(os,osmt)
-
-if not os.setenv then
-
- -- we still store them but they won't be seen in
- -- child processes although we might pass them some day
- -- using command concatination
-
- local env, getenv = { }, os.getenv
-
- function os.setenv(k,v)
- env[k] = v
- end
-
- function os.getenv(k)
- return env[k] or getenv(k)
- end
-
-end
-
--- we can use HOSTTYPE on some platforms
-
-local name, platform = os.name or "linux", os.getenv("MTX_PLATFORM") or ""
-
-local function guess()
- local architecture = os.resultof("uname -m") or ""
- if architecture ~= "" then
- return architecture
- end
- architecture = os.getenv("HOSTTYPE") or ""
- if architecture ~= "" then
- return architecture
- end
- return os.resultof("echo $HOSTTYPE") or ""
-end
-
-if platform ~= "" then
-
- os.platform = platform
-
-elseif os.type == "windows" then
-
- -- we could set the variable directly, no function needed here
-
- function os.resolvers.platform(t,k)
- local platform, architecture = "", os.getenv("PROCESSOR_ARCHITECTURE") or ""
- if find(architecture,"AMD64") then
- platform = "mswin-64"
- else
- platform = "mswin"
- end
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-
-elseif name == "linux" then
-
- function os.resolvers.platform(t,k)
- -- we sometims have HOSTTYPE set so let's check that first
- local platform, architecture = "", os.getenv("HOSTTYPE") or os.resultof("uname -m") or ""
- if find(architecture,"x86_64") then
- platform = "linux-64"
- elseif find(architecture,"ppc") then
- platform = "linux-ppc"
- else
- platform = "linux"
- end
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-
-elseif name == "macosx" then
-
- --[[
- Identifying the architecture of OSX is quite a mess and this
- is the best we can come up with. For some reason $HOSTTYPE is
- a kind of pseudo environment variable, not known to the current
- environment. And yes, uname cannot be trusted either, so there
- is a change that you end up with a 32 bit run on a 64 bit system.
- Also, some proper 64 bit intel macs are too cheap (low-end) and
- therefore not permitted to run the 64 bit kernel.
- ]]--
-
- function os.resolvers.platform(t,k)
- -- local platform, architecture = "", os.getenv("HOSTTYPE") or ""
- -- if architecture == "" then
- -- architecture = os.resultof("echo $HOSTTYPE") or ""
- -- end
- local platform, architecture = "", os.resultof("echo $HOSTTYPE") or ""
- if architecture == "" then
- -- print("\nI have no clue what kind of OSX you're running so let's assume an 32 bit intel.\n")
- platform = "osx-intel"
- elseif find(architecture,"i386") then
- platform = "osx-intel"
- elseif find(architecture,"x86_64") then
- platform = "osx-64"
- else
- platform = "osx-ppc"
- end
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-
-elseif name == "sunos" then
-
- function os.resolvers.platform(t,k)
- local platform, architecture = "", os.resultof("uname -m") or ""
- if find(architecture,"sparc") then
- platform = "solaris-sparc"
- else -- if architecture == 'i86pc'
- platform = "solaris-intel"
- end
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-
-elseif name == "freebsd" then
-
- function os.resolvers.platform(t,k)
- local platform, architecture = "", os.resultof("uname -m") or ""
- if find(architecture,"amd64") then
- platform = "freebsd-amd64"
- else
- platform = "freebsd"
- end
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-
-elseif name == "kfreebsd" then
-
- function os.resolvers.platform(t,k)
- -- we sometims have HOSTTYPE set so let's check that first
- local platform, architecture = "", os.getenv("HOSTTYPE") or os.resultof("uname -m") or ""
- if find(architecture,"x86_64") then
- platform = "kfreebsd-64"
- else
- platform = "kfreebsd-i386"
- end
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-
-else
-
- -- platform = "linux"
- -- os.setenv("MTX_PLATFORM",platform)
- -- os.platform = platform
-
- function os.resolvers.platform(t,k)
- local platform = "linux"
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-
-end
-
--- beware, we set the randomseed
-
--- from wikipedia: Version 4 UUIDs use a scheme relying only on random numbers. This algorithm sets the
--- version number as well as two reserved bits. All other bits are set using a random or pseudorandom
--- data source. Version 4 UUIDs have the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx with hexadecimal
--- digits x and hexadecimal digits 8, 9, A, or B for y. e.g. f47ac10b-58cc-4372-a567-0e02b2c3d479.
---
--- as we don't call this function too often there is not so much risk on repetition
-
-local t = { 8, 9, "a", "b" }
-
-function os.uuid()
- return format("%04x%04x-4%03x-%s%03x-%04x-%04x%04x%04x",
- random(0xFFFF),random(0xFFFF),
- random(0x0FFF),
- t[ceil(random(4))] or 8,random(0x0FFF),
- random(0xFFFF),
- random(0xFFFF),random(0xFFFF),random(0xFFFF)
- )
-end
-
-local d
-
-function os.timezone(delta)
- d = d or tonumber(tonumber(os.date("%H")-os.date("!%H")))
- if delta then
- if d > 0 then
- return format("+%02i:00",d)
- else
- return format("-%02i:00",-d)
- end
- else
- return 1
- end
-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.mkiv",
- 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, sub, char = string.find, string.gmatch, string.match, string.gsub, string.sub, string.char
-local lpegmatch = lpeg.match
-
-function file.removesuffix(filename)
- return (gsub(filename,"%.[%a%d]+$",""))
-end
-
-function file.addsuffix(filename, suffix)
- if not suffix or suffix == "" then
- return filename
- elseif 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,default)
- return match(name,"^.+%.([^/\\]-)$") or default or ""
-end
-
-file.suffix = file.extname
-
---~ 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
-
-local trick_1 = char(1)
-local trick_2 = "^" .. trick_1 .. "/+"
-
-function file.join(...)
- local lst = { ... }
- local a, b = lst[1], lst[2]
- if a == "" then
- lst[1] = trick_1
- elseif b and find(a,"^/+$") and find(b,"^/") then
- lst[1] = ""
- lst[2] = gsub(b,"^/+","")
- end
- local pth = concat(lst,"/")
- 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
- pth = gsub(pth,trick_2,"")
- return (gsub(pth,"//+","/"))
-end
-
---~ print(file.join("//","/y"))
---~ print(file.join("/","/y"))
---~ print(file.join("","/y"))
---~ print(file.join("/x/","/y"))
---~ 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.iswritable(name)
- local a = lfs.attributes(name) or lfs.attributes(file.dirname(name,"."))
- return a and sub(a.permissions,2,2) == "w"
-end
-
-function file.isreadable(name)
- local a = lfs.attributes(name)
- return a and sub(a.permissions,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
-
-local checkedsplit = string.checkedsplit
-
-function file.split_path(str,separator)
- str = gsub(str,"\\","/")
- return checkedsplit(str,separator or io.pathseparator)
-end
-
-function file.join_path(tab)
- return concat(tab,io.pathseparator) -- can have trailing //
-end
-
--- we can hash them weakly
-
-function file.collapse_path(str)
- str = gsub(str,"\\","/")
- if find(str,"/") then
- str = gsub(str,"^%./",(gsub(lfs.currentdir(),"\\","/")) .. "/") -- ./xx in qualified
- 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,"^%./","") -- ./xx in qualified
- str = gsub(str,"/%.$","")
- end
- if str == "" then str = "." end
- return str
-end
-
---~ print(file.collapse_path("/a"))
---~ 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 lpegmatch(pattern,name) or ""
---~ end
-
---~ local pattern = lpeg.Cs(((period * noperiod^1 * -1)/"" + 1)^1)
-
---~ function file.removesuffix(name)
---~ return lpegmatch(pattern,name)
---~ end
-
---~ local pattern = (noslashes^0 * slashes)^1 * lpeg.C(noslashes^1) * -1
-
---~ function file.basename(name)
---~ return lpegmatch(pattern,name) or name
---~ end
-
---~ local pattern = (noslashes^0 * slashes)^1 * lpeg.Cp() * noslashes^1 * -1
-
---~ function file.dirname(name)
---~ local p = lpegmatch(pattern,name)
---~ if p then
---~ return sub(name,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 = lpegmatch(pattern,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 = lpegmatch(pattern,name)
---~ if p then
---~ return sub(name,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 = lpegmatch(pattern,name)
---~ if b then
---~ return sub(name,a,b-2)
---~ elseif a then
---~ return sub(name,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 lpegmatch(qualified,filename) ~= nil
-end
-
-function file.is_rootbased_path(filename)
- return lpegmatch(rootbased,filename) ~= nil
-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 lpegmatch(pattern,str)
-end
-
--- function test(t) for k, v in next, 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" }
-
---~ -- todo:
---~
---~ if os.type == "windows" then
---~ local currentdir = lfs.currentdir
---~ function lfs.currentdir()
---~ return (gsub(currentdir(),"\\","/"))
---~ end
---~ 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 (gsub(data,"%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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local char, gmatch, gsub = string.char, string.gmatch, string.gsub
-local tonumber, type = tonumber, type
-local lpegmatch = lpeg.match
-
--- 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)
-
--- we assume schemes with more than 1 character (in order to avoid problems with windows disks)
-
-local scheme = lpeg.Cs((escaped+(1-colon-slash-qmark-hash))^2) * 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)
-
--- todo: reconsider Ct as we can as well have five return values (saves a table)
--- so we can have two parsers, one with and one without
-
-function url.split(str)
- return (type(str) == "string" and lpegmatch(parser,str)) or str
-end
-
--- todo: cache them
-
-function url.hashed(str)
- local s = url.split(str)
- local somescheme = s[1] ~= ""
- return {
- scheme = (somescheme and s[1]) or "file",
- authority = s[2],
- path = s[3],
- query = s[4],
- fragment = s[5],
- original = str,
- noscheme = not somescheme,
- }
-end
-
-function url.hasscheme(str)
- return url.split(str)[1] ~= ""
-end
-
-function url.addscheme(str,scheme)
- return (url.hasscheme(str) and str) or ((scheme or "file:///") .. str)
-end
-
-function url.construct(hash)
- local fullurl = hash.sheme .. "://".. hash.authority .. hash.path
- if hash.query then
- fullurl = fullurl .. "?".. hash.query
- end
- if hash.fragment then
- fullurl = fullurl .. "?".. hash.fragment
- end
- return fullurl
-end
-
-function url.filename(filename)
- local t = url.hashed(filename)
- return (t.scheme == "file" and (gsub(t.path,"^/([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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- dir.expand_name will be merged with cleanpath and collapsepath
-
-local type = type
-local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub
-local lpegmatch = lpeg.match
-
-dir = dir or { }
-
--- handy
-
-function dir.current()
- return (gsub(lfs.currentdir(),"\\","/"))
-end
-
--- 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 function collect_pattern(path,patt,recurse,result)
- local ok, scanner
- result = result or { }
- 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 attr = attributes(full)
- local mode = attr.mode
- if mode == 'file' then
- if find(full,patt) then
- result[name] = attr
- end
- elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
- attr.list = collect_pattern(full,patt,recurse)
- result[name] = attr
- end
- end
- end
- return result
-end
-
-dir.collect_pattern = collect_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(t) == "function" then
- if type(str) == "table" then
- for s=1,#str do
- glob(str[s],t)
- end
- elseif lfs.isfile(str) then
- t(str)
- else
- local split = lpegmatch(pattern,str)
- if split then
- local root, path, base = split[1], split[2], split[3]
- local recurse = find(base,"%*%*")
- local start = root .. path
- local result = lpegmatch(filter,start .. base)
- glob_pattern(start,result,recurse,t)
- end
- end
- else
- 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 = lpegmatch(pattern,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 = lpegmatch(filter,start .. base)
- glob_pattern(start,result,recurse,action)
- return t
- else
- return { }
- end
- 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 -- os.type == "windows"
-
- function dir.mkdirs(...)
- local str, pth, t = "", "", { ... }
- for i=1,#t do
- local s = t[i]
- 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 = match(str,"^(//)(//*)(.*)$")
- if first then
- -- empty network path == local path
- else
- first, last = match(str,"^(//)/*(.-)$")
- if first then
- middle, last = match(str,"([^/]+)/+(.-)$")
- if middle then
- pth = "//" .. middle
- else
- pth = "//" .. last
- last = ""
- end
- else
- first, middle, last = match(str,"^([a-zA-Z]:)(/*)(.-)$")
- if first then
- pth, drive = first .. middle, true
- else
- middle, last = match(str,"^(/*)(.-)$")
- 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) -- will be merged with cleanpath and collapsepath
- local first, nothing, last = match(str,"^(//)(//*)(.*)$")
- if first then
- first = dir.current() .. "/"
- end
- if not first then
- first, last = match(str,"^(//)/*(.*)$")
- end
- if not first then
- first, last = match(str,"^([a-zA-Z]:)(.*)$")
- if first and not find(last,"^/") then
- local d = lfs.currentdir()
- if lfs.chdir(first) then
- first = dir.current()
- end
- lfs.chdir(d)
- end
- end
- if not first then
- first, last = dir.current(), str
- end
- last = gsub(last,"//","/")
- last = gsub(last,"/%./","/")
- last = gsub(last,"^/*","")
- first = gsub(first,"/*$","")
- if last == "" then
- return first
- else
- return first .. "/" .. last
- end
- end
-
-else
-
- function dir.mkdirs(...)
- local str, pth, t = "", "", { ... }
- for i=1,#t do
- local s = t[i]
- if s ~= "" then
- if str ~= "" then
- str = str .. "/" .. s
- else
- str = s
- end
- end
- end
- str = gsub(str,"/+","/")
- 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) -- will be merged with cleanpath and collapsepath
- if not find(str,"^/") then
- str = lfs.currentdir() .. "/" .. str
- end
- str = gsub(str,"//","/")
- str = gsub(str,"/%./","/")
- 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.mkiv",
- 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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-if not unicode then
-
- unicode = { utf8 = { } }
-
- local floor, char = math.floor, string.char
-
- function unicode.utf8.utfchar(n)
- if n < 0x80 then
- return char(n)
- elseif n < 0x800 then
- return char(0xC0 + floor(n/0x40)) .. char(0x80 + (n % 0x40))
- elseif n < 0x10000 then
- return char(0xE0 + floor(n/0x1000)) .. char(0x80 + (floor(n/0x40) % 0x40)) .. char(0x80 + (n % 0x40))
- elseif n < 0x40000 then
- return char(0xF0 + floor(n/0x40000)) .. char(0x80 + floor(n/0x1000)) .. char(0x80 + (floor(n/0x40) % 0x40)) .. char(0x80 + (n % 0x40))
- else -- wrong:
- -- return char(0xF1 + floor(n/0x1000000)) .. char(0x80 + floor(n/0x40000)) .. char(0x80 + floor(n/0x1000)) .. char(0x80 + (floor(n/0x40) % 0x40)) .. char(0x80 + (n % 0x40))
- return "?"
- end
- end
-
-end
-
-utf = utf or unicode.utf8
-
-local concat, utfchar, utfgsub = table.concat, utf.char, utf.gsub
-local char, byte, find, bytepairs = string.char, string.byte, string.find, string.bytepairs
-
--- 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'
-}
-
--- \000 fails in <= 5.0 but is valid in >=5.1 where %z is depricated
-
-function unicode.utftype(f)
- local str = f:read(4)
- if not str then
- f:seek('set')
- return 0
- -- elseif find(str,"^%z%z\254\255") then -- depricated
- -- elseif find(str,"^\000\000\254\255") then -- not permitted and bugged
- elseif find(str,"\000\000\254\255",1,true) then -- seems to work okay (TH)
- return 4
- -- elseif find(str,"^\255\254%z%z") then -- depricated
- -- elseif find(str,"^\255\254\000\000") then -- not permitted and bugged
- elseif find(str,"\255\254\000\000",1,true) then -- seems to work okay (TH)
- 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.mkiv",
- 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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- hm, quite unreadable
-
-local gsub = string.gsub
-local concat = table.concat
-local type, next = type, next
-
-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 = gsub(data,"%-%-~[^\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 (gsub(data,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 = gsub(data,"%-%-~[^\n]*\n","")
---~ data = 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 i=1,#libs do
- local lib = libs[i]
- for j=1,#list do
- local pth = gsub(list[j],"\\","/") -- 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 i=1,#libs do
- local lib = libs[i]
- 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",concat(right," "))
- end
- if #wrong > 0 then
- utils.report("skipped libraries: %s",concat(wrong," "))
- end
- else
- utils.report("no valid library path found")
- end
- return 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 ['l-aux'] = {
- version = 1.001,
- comment = "companion to luat-lib.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- for inline, no store split : for s in string.gmatch(str,",* *([^,]+)") do .. end
-
-aux = aux or { }
-
-local concat, format, gmatch = table.concat, string.format, string.gmatch
-local tostring, type = tostring, type
-local lpegmatch = lpeg.match
-
-local P, R, V = lpeg.P, lpeg.R, lpeg.V
-
-local escape, left, right = P("\\"), P('{'), P('}')
-
-lpeg.patterns.balanced = P {
- [1] = ((escape * (left+right)) + (1 - (left+right)) + V(2))^0,
- [2] = left * V(1) * right
-}
-
-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 value = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0)
-
-local key = lpeg.C((1-equal-comma)^1)
-local pattern_a = (space+comma)^0 * (key * equal * value + key * lpeg.C(""))
-local pattern_c = (space+comma)^0 * (key * equal * value)
-
-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
-local pattern_c_s = (pattern_c/set)^1
-
-aux.settings_to_hash_pattern_a = pattern_a_s
-aux.settings_to_hash_pattern_b = pattern_b_s
-aux.settings_to_hash_pattern_c = pattern_c_s
-
-function aux.make_settings_to_hash_pattern(set,how)
- if how == "strict" then
- return (pattern_c/set)^1
- elseif how == "tolerant" then
- return (pattern_b/set)^1
- else
- return (pattern_a/set)^1
- end
-end
-
-function aux.settings_to_hash(str,existing)
- if str and str ~= "" then
- hash = existing or { }
- if moretolerant then
- lpegmatch(pattern_b_s,str)
- else
- lpegmatch(pattern_a_s,str)
- end
- return hash
- else
- return { }
- end
-end
-
-function aux.settings_to_hash_tolerant(str,existing)
- if str and str ~= "" then
- hash = existing or { }
- lpegmatch(pattern_b_s,str)
- return hash
- else
- return { }
- end
-end
-
-function aux.settings_to_hash_strict(str,existing)
- if str and str ~= "" then
- hash = existing or { }
- lpegmatch(pattern_c_s,str)
- return next(hash) and hash
- else
- return nil
- end
-end
-
-local separator = 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*(separator*value)^0)
-
--- "aap, {noot}, mies" : outer {} removes, leading spaces ignored
-
-aux.settings_to_array_pattern = pattern
-
--- we could use a weak table as cache
-
-function aux.settings_to_array(str)
- if not str or str == "" then
- return { }
- else
- return lpegmatch(pattern,str)
- end
-end
-
-local function set(t,v)
- t[#t+1] = v
-end
-
-local value = lpeg.P(lpeg.Carg(1)*value) / set
-local pattern = value*(separator*value)^0 * lpeg.Carg(1)
-
-function aux.add_settings_to_array(t,str)
- return lpegmatch(pattern,str,nil,t)
-end
-
-function aux.hash_to_string(h,separator,yes,no,strict,omit)
- if h then
- local t, s = { }, table.sortedkeys(h)
- omit = omit and table.tohash(omit)
- for i=1,#s do
- local key = s[i]
- if not omit or not omit[key] then
- local value = h[key]
- if type(value) == "boolean" then
- if yes and no then
- if value then
- t[#t+1] = key .. '=' .. yes
- elseif not strict then
- t[#t+1] = key .. '=' .. no
- end
- elseif value or not strict then
- t[#t+1] = key .. '=' .. tostring(value)
- end
- else
- t[#t+1] = key .. '=' .. value
- end
- end
- end
- return concat(t,separator or ",")
- else
- return ""
- end
-end
-
-function aux.array_to_string(a,separator)
- if a then
- return concat(a,separator or ",")
- else
- return ""
- end
-end
-
-function aux.settings_to_set(str,t)
- t = t or { }
- for s in gmatch(str,"%s*([^,]+)") do
- t[s] = true
- end
- return t
-end
-
-local value = lbrace * lpeg.C((nobrace + nested)^0) * rbrace
-local pattern = lpeg.Ct((space + value)^0)
-
-function aux.arguments_to_table(str)
- return lpegmatch(pattern,str)
-end
-
--- temporary here
-
-function aux.getparameters(self,class,parentclass,settings)
- local sc = self[class]
- if not sc then
- sc = table.clone(self[parent])
- self[class] = sc
- end
- aux.settings_to_hash(settings,sc)
-end
-
--- temporary here
-
-local digit = lpeg.R("09")
-local period = lpeg.P(".")
-local zero = lpeg.P("0")
-local trailingzeros = zero^0 * -digit -- suggested by Roberto R
-local case_1 = period * trailingzeros / ""
-local case_2 = period * (digit - trailingzeros)^1 * (trailingzeros / "")
-local number = digit^1 * (case_1 + case_2)
-local stripper = lpeg.Cs((number + 1)^0)
-
---~ local sample = "bla 11.00 bla 11 bla 0.1100 bla 1.00100 bla 0.00 bla 0.001 bla 1.1100 bla 0.100100100 bla 0.00100100100"
---~ collectgarbage("collect")
---~ str = string.rep(sample,10000)
---~ local ts = os.clock()
---~ lpegmatch(stripper,str)
---~ print(#str, os.clock()-ts, lpegmatch(stripper,sample))
-
-lpeg.patterns.strip_zeros = stripper
-
-function aux.strip_zeros(str)
- return lpegmatch(stripper,str)
-end
-
-function aux.definetable(target) -- defines undefined tables
- local composed, t = nil, { }
- for name in gmatch(target,"([^%.]+)") do
- if composed then
- composed = composed .. "." .. name
- else
- composed = name
- end
- t[#t+1] = format("%s = %s or { }",composed,composed)
- end
- return concat(t,"\n")
-end
-
-function aux.accesstable(target)
- local t = _G
- for name in gmatch(target,"([^%.]+)") do
- t = t[name]
- end
- return t
-end
-
--- as we use this a lot ...
-
---~ function aux.cachefunction(action,weak)
---~ local cache = { }
---~ if weak then
---~ setmetatable(cache, { __mode = "kv" } )
---~ end
---~ local function reminder(str)
---~ local found = cache[str]
---~ if not found then
---~ found = action(str)
---~ cache[str] = found
---~ end
---~ return found
---~ end
---~ return reminder, cache
---~ end
-
-
-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 trac-tra.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- the <anonymous> tag is kind of generic and used for functions that are not
--- bound to a variable, like node.new, node.copy etc (contrary to for instance
--- node.has_attribute which is bound to a has_attribute local variable in mkiv)
-
-local debug = require "debug"
-
-local getinfo = debug.getinfo
-local type, next = type, next
-local concat = table.concat
-local format, find, lower, gmatch, gsub = string.format, string.find, string.lower, string.gmatch, string.gsub
-
-debugger = debugger or { }
-
-local counters = { }
-local names = { }
-
--- one
-
-local function hook()
- local f = getinfo(2,"f").func
- local n = getinfo(2,"Sn")
--- if n.what == "C" and n.name then print (n.namewhat .. ': ' .. n.name) end
- if f then
- local cf = counters[f]
- if cf == nil then
- counters[f] = 1
- names[f] = n
- else
- counters[f] = cf + 1
- end
- end
-end
-local function getname(func)
- local n = names[func]
- if n then
- if n.what == "C" then
- return n.name or '<anonymous>'
- else
- -- source short_src linedefined what name namewhat nups func
- local name = n.name or n.namewhat or n.what
- if not name or name == "" then name = "?" end
- return format("%s : %s : %s", n.short_src or "unknown source", n.linedefined or "--", name)
- end
- else
- return "unknown"
- end
-end
-function debugger.showstats(printer,threshold)
- printer = printer or texio.write or print
- threshold = threshold or 0
- local total, grandtotal, functions = 0, 0, 0
- printer("\n") -- ugly but ok
- -- table.sort(counters)
- for func, count in next, counters do
- if count > threshold then
- local name = getname(func)
- if not find(name,"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 next, 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)
-
-setters = setters or { }
-setters.data = setters.data or { }
-
---~ local function set(t,what,value)
---~ local data, done = t.data, t.done
---~ if type(what) == "string" then
---~ what = aux.settings_to_array(what) -- inefficient but ok
---~ end
---~ for i=1,#what do
---~ local w = what[i]
---~ 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 set(t,what,value)
- local data, done = t.data, t.done
- if type(what) == "string" then
- what = aux.settings_to_hash(what) -- inefficient but ok
- end
- for w, v in next, what do
- if v == "" then
- v = value
- else
- v = toboolean(v)
- end
- 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](v)
- end
- end
- end
- end
-end
-
-local function reset(t)
- for d, f in next, t.data do
- for i=1,#f do
- f[i](false)
- end
- end
-end
-
-local function enable(t,what)
- set(t,what,true)
-end
-
-local function disable(t,what)
- local data = t.data
- if not what or what == "" then
- t.done = { }
- reset(t)
- else
- set(t,what,false)
- end
-end
-
-function setters.register(t,what,...)
- local data = t.data
- 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(t,fnc,value,nesting) end
- end
- end
-end
-
-function setters.enable(t,what)
- local e = t.enable
- t.enable, t.done = enable, { }
- enable(t,string.simpleesc(tostring(what)))
- t.enable, t.done = e, { }
-end
-
-function setters.disable(t,what)
- local e = t.disable
- t.disable, t.done = disable, { }
- disable(t,string.simpleesc(tostring(what)))
- t.disable, t.done = e, { }
-end
-
-function setters.reset(t)
- t.done = { }
- reset(t)
-end
-
-function setters.list(t) -- pattern
- local list = table.sortedkeys(t.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
-
-function setters.show(t)
- commands.writestatus("","")
- local list = setters.list(t)
- for k=1,#list do
- commands.writestatus(t.name,list[k])
- end
- commands.writestatus("","")
-end
-
--- we could have used a bit of oo and the trackers:enable syntax but
--- there is already a lot of code around using the singular tracker
-
--- we could make this into a module
-
-function setters.new(name)
- local t
- t = {
- data = { },
- name = name,
- enable = function(...) setters.enable (t,...) end,
- disable = function(...) setters.disable (t,...) end,
- register = function(...) setters.register(t,...) end,
- list = function(...) setters.list (t,...) end,
- show = function(...) setters.show (t,...) end,
- }
- setters.data[name] = t
- return t
-end
-
-trackers = setters.new("trackers")
-directives = setters.new("directives")
-experiments = setters.new("experiments")
-
--- nice trick: we overload two of the directives related functions with variants that
--- do tracing (itself using a tracker) .. proof of concept
-
-local trace_directives = false local trace_directives = false trackers.register("system.directives", function(v) trace_directives = v end)
-local trace_experiments = false local trace_experiments = false trackers.register("system.experiments", function(v) trace_experiments = v end)
-
-local e = directives.enable
-local d = directives.disable
-
-function directives.enable(...)
- commands.writestatus("directives","enabling: %s",concat({...}," "))
- e(...)
-end
-
-function directives.disable(...)
- commands.writestatus("directives","disabling: %s",concat({...}," "))
- d(...)
-end
-
-local e = experiments.enable
-local d = experiments.disable
-
-function experiments.enable(...)
- commands.writestatus("experiments","enabling: %s",concat({...}," "))
- e(...)
-end
-
-function experiments.disable(...)
- commands.writestatus("experiments","disabling: %s",concat({...}," "))
- d(...)
-end
-
--- a useful example
-
-directives.register("system.nostatistics", function(v)
- statistics.enable = not v
-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.mkiv",
- 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_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end)
-
-local format, sub, match, gsub, find = string.format, string.sub, string.match, string.gsub, string.find
-local unquote, quote = string.unquote, string.quote
-
--- 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=1,#arg do
- local argument = arg[index]
- if index > 0 then
- local flag, value = match(argument,"^%-+(.-)=(.-)$")
- if flag then
- arguments[flag] = unquote(value or "")
- else
- flag = match(argument,"^%-+(.+)")
- 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 = table.sortedkeys(arguments)
- for k=1,#sortedflags do
- sortedflags[k] = "^" .. sortedflags[k]
- end
- environment.sortedflags = sortedflags
- end
- -- example of potential clash: ^mode ^modefile
- for k=1,#sortedflags do
- local v = sortedflags[k]
- if find(name,v) then
- return arguments[sub(v,2,#v)]
- end
- end
- end
- return nil
-end
-
-environment.argument("x",true)
-
-function environment.split_arguments(separator) -- rather special, cut-off before separator
- local done, before, after = false, { }, { }
- local original_arguments = environment.original_arguments
- for k=1,#original_arguments do
- local v = original_arguments[k]
- 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 = unquote(a)
- return a
- elseif #arg > 0 then
- local result = { }
- for i=1,#arg do
- local a = arg[i]
- a = resolvers.resolve(a)
- a = unquote(a)
- a = gsub(a,'"','\\"') -- tricky
- if find(a," ") then
- result[#result+1] = quote(a)
- 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 remove the " then and add them later)
- local newarg, instring = { }, false
-
- for index=1,#arg do
- local argument = arg[index]
- if find(argument,"^\"") then
- newarg[#newarg+1] = gsub(argument,"^\"","")
- if not find(argument,"\"$") then
- instring = true
- end
- elseif find(argument,"\"$") then
- newarg[#newarg] = newarg[#newarg] .. " " .. gsub(argument,"\"$","")
- 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_locating then
- logs.report("fileio","loading file %s", fullname)
- end
- return environment.loadedluacode(fullname)
- else
- if trace_locating 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_locating 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_locating 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_locating 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 trace_locating 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 trac-inf.mkiv",
- 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
-
-local notimer
-
-function statistics.hastimer(instance)
- return instance and instance.starttime
-end
-
-function statistics.resettiming(instance)
- if not instance then
- notimer = { timing = 0, loadtime = 0 }
- else
- instance.timing, instance.loadtime = 0, 0
- end
-end
-
-function statistics.starttiming(instance)
- if not instance then
- notimer = { }
- instance = notimer
- end
- 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
- else
---~ logs.report("system","nested timing (%s)",tostring(instance))
- end
- instance.timing = it + 1
-end
-
-function statistics.stoptiming(instance, report)
- if not instance then
- instance = notimer
- end
- 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)
- if not instance then
- instance = notimer
- end
- return format("%0.3f",(instance and instance.loadtime) or 0)
-end
-
-function statistics.elapsedindeed(instance)
- if not instance then
- instance = notimer
- end
- local t = (instance and instance.loadtime) or 0
- return t > statistics.threshold
-end
-
-function statistics.elapsedseconds(instance,rest) -- returns nil if 0 seconds
- if statistics.elapsedindeed(instance) then
- return format("%s seconds %s", statistics.elapsedtime(instance),rest or "")
- end
-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
- texio.write_nl("") -- final newline
- 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
-
--- where, not really the best spot for this:
-
-commands = commands or { }
-
-local timer
-
-function commands.resettimer()
- statistics.resettiming(timer)
- statistics.starttiming(timer)
-end
-
-function commands.elapsedtime()
- statistics.stoptiming(timer)
- tex.sprint(statistics.elapsedtime(timer))
-end
-
-commands.resettimer()
-
-
-end -- of closure
-
-do -- create closure to overcome 200 locals limit
-
-if not modules then modules = { } end modules ['trac-log'] = {
- version = 1.001,
- comment = "companion to trac-log.mkiv",
- 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
-
---~ io.stdout:setvbuf("no")
---~ io.stderr:setvbuf("no")
-
-local write_nl, write = texio.write_nl or print, texio.write or io.write
-local format, gmatch = string.format, string.gmatch
-local texcount = tex and tex.count
-
-if texlua then
- write_nl = print
- write = io.write
-end
-
---[[ldx--
-<p>This is a prelude to a more extensive logging module. For the sake
-of parsing log files, in addition to the standard logging we will
-provide an <l n='xml'/> structured file. Actually, any logging that
-is hooked into callbacks will be \XML\ by default.</p>
---ldx]]--
-
-logs = logs or { }
-logs.xml = logs.xml or { }
-logs.tex = logs.tex or { }
-
---[[ldx--
-<p>This looks pretty ugly but we need to speed things up a bit.</p>
---ldx]]--
-
-logs.moreinfo = [[
-more information about ConTeXt and the tools that come with it can be found at:
-
-maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
-webpage : http://www.pragma-ade.nl / http://tex.aanhet.net
-wiki : http://contextgarden.net
-]]
-
-logs.levels = {
- ['error'] = 1,
- ['warning'] = 2,
- ['info'] = 3,
- ['debug'] = 4,
-}
-
-logs.functions = {
- 'report', 'start', 'stop', 'push', 'pop', 'line', 'direct',
- 'start_run', 'stop_run',
- 'start_page_number', 'stop_page_number',
- 'report_output_pages', 'report_output_log',
- 'report_tex_stat', 'report_job_stat',
- 'show_open', 'show_close', 'show_load',
-}
-
-logs.tracers = {
-}
-
-logs.level = 0
-logs.mode = string.lower((os.getenv("MTX.LOG.MODE") or os.getenv("MTX_LOG_MODE") or "tex"))
-
-function logs.set_level(level)
- logs.level = logs.levels[level] or level
-end
-
-function logs.set_method(method)
- for _, v in next, logs.functions do
- logs[v] = logs[method][v] or function() end
- end
-end
-
--- tex logging
-
-function logs.tex.report(category,fmt,...) -- new
- if fmt then
- write_nl(category .. " | " .. format(fmt,...))
- else
- write_nl(category .. " |")
- end
-end
-
-function logs.tex.line(fmt,...) -- new
- if fmt then
- write_nl(format(fmt,...))
- else
- write_nl("")
- end
-end
-
---~ function logs.tex.start_page_number()
---~ local real, user, sub = texcount.realpageno, texcount.userpageno, texcount.subpageno
---~ 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
-
-local real, user, sub
-
-function logs.tex.start_page_number()
- real, user, sub = texcount.realpageno, texcount.userpageno, texcount.subpageno
-end
-
-function logs.tex.stop_page_number()
- if real > 0 then
- if user > 0 then
- if sub > 0 then
- logs.report("pages", "flushing realpage %s, userpage %s, subpage %s",real,user,sub)
- else
- logs.report("pages", "flushing realpage %s, userpage %s",real,user)
- end
- else
- logs.report("pages", "flushing realpage %s",real)
- end
- else
- logs.report("pages", "flushing page")
- end
- io.flush()
-end
-
-logs.tex.report_job_stat = statistics.show_job_stat
-
--- xml logging
-
-function logs.xml.report(category,fmt,...) -- new
- if fmt then
- write_nl(format("<r category='%s'>%s</r>",category,format(fmt,...)))
- else
- write_nl(format("<r category='%s'/>",category))
- end
-end
-function logs.xml.line(fmt,...) -- new
- if fmt then
- write_nl(format("<r>%s</r>",format(fmt,...)))
- else
- write_nl("<r/>")
- end
-end
-
-function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end
-function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end
-function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end
-function logs.xml.pop () if logs.level > 0 then tw(" -->" ) end end
-
-function logs.xml.start_run()
- write_nl("<?xml version='1.0' standalone='yes'?>")
- write_nl("<job>") -- xmlns='www.pragma-ade.com/luatex/schemas/context-job.rng'
- write_nl("")
-end
-
-function logs.xml.stop_run()
- write_nl("</job>")
-end
-
-function logs.xml.start_page_number()
- write_nl(format("<p real='%s' page='%s' sub='%s'", texcount.realpageno, texcount.userpageno, texcount.subpageno))
-end
-
-function logs.xml.stop_page_number()
- write("/>")
- write_nl("")
-end
-
-function logs.xml.report_output_pages(p,b)
- write_nl(format("<v k='pages' v='%s'/>", p))
- write_nl(format("<v k='bytes' v='%s'/>", b))
- write_nl("")
-end
-
-function logs.xml.report_output_log()
-end
-
-function logs.xml.report_tex_stat(k,v)
- texiowrite_nl("log","<v k='"..k.."'>"..tostring(v).."</v>")
-end
-
-local level = 0
-
-function logs.xml.show_open(name)
- level = level + 1
- texiowrite_nl(format("<f l='%s' n='%s'>",level,name))
-end
-
-function logs.xml.show_close(name)
- texiowrite("</f> ")
- level = level - 1
-end
-
-function logs.xml.show_load(name)
- texiowrite_nl(format("<f l='%s' n='%s'/>",level+1,name))
-end
-
---
-
-local name, banner = 'report', 'context'
-
-local function report(category,fmt,...)
- if fmt then
- write_nl(format("%s | %s: %s",name,category,format(fmt,...)))
- elseif category then
- write_nl(format("%s | %s",name,category))
- else
- write_nl(format("%s |",name))
- end
-end
-
-local function simple(fmt,...)
- if fmt then
- write_nl(format("%s | %s",name,format(fmt,...)))
- else
- write_nl(format("%s |",name))
- end
-end
-
-function logs.setprogram(_name_,_banner_,_verbose_)
- name, banner = _name_, _banner_
- if _verbose_ then
- trackers.enable("resolvers.locating")
- 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.locating")
- else
- trackers.disable("resolvers.locating")
- end
- logs.verbose = what or false
-end
-
-function logs.extendbanner(_banner_,_verbose_)
- banner = banner .. " | ".. _banner_
- if _verbose_ ~= nil then
- logs.setverbose(what)
- end
-end
-
-logs.verbose = false
-logs.report = logs.tex.report
-logs.simple = logs.tex.report
-
-function logs.reportlines(str) -- todo: <lines></lines>
- for line in gmatch(str,"(.-)[\n\r]") do
- logs.report(line)
- end
-end
-
-function logs.reportline() -- for scripts too
- logs.report()
-end
-
-logs.simpleline = logs.reportline
-
-function logs.reportbanner() -- for scripts too
- logs.report(banner)
-end
-
-function logs.help(message,option)
- logs.reportbanner()
- 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
-
-function logs.fatal(where,...)
- logs.report(where,"fatal error: %s, aborting now",format(...))
- os.exit()
-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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files",
-}
-
--- 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]
--- 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 lpegmatch = lpeg.match
-
-local trace_locating, trace_detail, trace_expansions = false, false, false
-
-trackers.register("resolvers.locating", function(v) trace_locating = v end)
-trackers.register("resolvers.details", function(v) trace_detail = v end)
-trackers.register("resolvers.expansions", function(v) trace_expansions = v end) -- todo
-
-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.type == "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', 'dfont' }
-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 maps'] = 'cid' -- great, why no cid files
-alternatives['font feature files'] = 'fea' -- and fea files here
-alternatives['opentype fonts'] = 'otf'
-alternatives['truetype fonts'] = 'ttf'
-alternatives['truetype collections'] = 'ttc'
-alternatives['truetype dictionary'] = 'dfont'
-alternatives['type1 fonts'] = 'pfb'
-
--- obscure ones
-
-formats ['misc fonts'] = ''
-suffixes['misc fonts'] = { }
-
-formats ['sfd'] = 'SFDFONTS'
-suffixes ['sfd'] = { 'sfd' }
-alternatives['subfont definition files'] = 'sfd'
-
--- lib paths
-
-formats ['lib'] = 'CLUAINPUTS' -- new (needs checking)
-suffixes['lib'] = (os.libsuffix and { os.libsuffix }) or { 'dll', 'so' }
-
--- 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, iv = instance.environment, instance.variables
- local function fix(varname,default)
- local proname = varname .. "." .. instance.progname or "crap"
- local p, v = ie[proname], ie[varname] or iv[varname]
- if not ((p and p ~= "") or (v and v ~= "")) then
- iv[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
- -- this will go away some day
- fix("FONTFEATURES", ".;$TEXMF/fonts/{data,fea}//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
- fix("FONTCIDMAPS" , ".;$TEXMF/fonts/{data,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_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 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
-
-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
- if trace_expansions then
- logs.report("fileio","expanding variable '%s'",str)
- end
- t = t or { }
- str = gsub(str,",}",",@}")
- str = gsub(str,"{,","{@,")
- -- str = "@" .. str .. "@"
- local ok, done
- 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
- if trace_expansions then
- for k=1,#t do
- logs.report("fileio","% 4i: %s",k,t[k])
- 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)
-
-local args = environment and environment.original_arguments or arg -- this needs a cleanup
-
-resolvers.ownbin = resolvers.ownbin or args[-2] or arg[-2] or args[-1] or arg[-1] or arg[0] or "luatex"
-resolvers.ownbin = gsub(resolvers.ownbin,"\\","/")
-
-function resolvers.getownpath()
- local ownpath = resolvers.ownpath or os.selfdir
- if not ownpath or ownpath == "" or ownpath == "unset" then
- ownpath = args[-1] or arg[-1]
- ownpath = ownpath and file.dirname(gsub(ownpath,"\\","/"))
- if not ownpath or ownpath == "" then
- ownpath = args[-0] or arg[-0]
- ownpath = ownpath and file.dirname(gsub(ownpath,"\\","/"))
- end
- local binary = resolvers.ownbin
- if not ownpath or ownpath == "" then
- ownpath = ownpath and file.dirname(binary)
- end
- if not ownpath or ownpath == "" then
- if os.binsuffix ~= "" then
- binary = file.replacesuffix(binary,os.binsuffix)
- 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_locating and p ~= pp then
- logs.report("fileio","following symlink '%s' to '%s'",p,pp)
- end
- ownpath = pp
- lfs.chdir(olddir)
- else
- if trace_locating then
- logs.report("fileio","unable to check path '%s'",p)
- end
- ownpath = p
- end
- break
- end
- end
- end
- if not ownpath or ownpath == "" then
- ownpath = "."
- logs.report("fileio","forcing fallback ownpath .")
- elseif trace_locating then
- logs.report("fileio","using ownpath '%s'",ownpath)
- end
- end
- resolvers.ownpath = ownpath
- function resolvers.getownpath()
- return resolvers.ownpath
- end
- return ownpath
-end
-
-local own_places = { "SELFAUTOLOC", "SELFAUTODIR", "SELFAUTOPARENT", "TEXMFCNF" }
-
-local function identify_own()
- local ownpath = resolvers.getownpath() or dir.current()
- 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_locating 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')
- if lfs.isfile(lname) then
- local dname = file.dirname(fname) -- 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_locating then
- logs.report("fileio","loading configuration file %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_locating then
- logs.report("fileio","skipping configuration file '%s'", fname)
- end
- end
-end
-
-local function collapse_cnf_data() -- potential optimization: pass start index (setup and configuration are shared)
- local order = instance.order
- for i=1,#order do
- local c = order[i]
- 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()
- local cnffiles = instance.cnffiles
- for i=1,#cnffiles do
- load_cnf_file(cnffiles[i])
- end
- end
- -- instance.cnffiles contain complete names now !
- -- we still use a funny mix of cnf and new but soon
- -- we will switch to lua exclusively as we only use
- -- the file to collect the tree roots
- if #instance.cnffiles == 0 then
- if trace_locating then
- logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)")
- end
- else
- local cnffiles = instance.cnffiles
- instance.rootpath = cnffiles[1]
- for k=1,#cnffiles do
- instance.cnffiles[k] = file.collapse_path(cnffiles[k])
- 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]
- local luafiles = instance.luafiles
- for k=1,#luafiles do
- instance.luafiles[k] = file.collapse_path(luafiles[k])
- 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 '%s' appended",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 '%s' prepended",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()
- local texmfpaths = resolvers.clean_path_list('TEXMF')
- for i=1,#texmfpaths do
- local path = texmfpaths[i]
- if trace_locating 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 '%s' found",specification)
- end
- resolvers.append_hash('file',specification,filename)
- elseif trace_locating then
- logs.report("fileio","tex locator '%s' not found",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
- local hashes = instance.hashes
- for k=1,#hashes do
- local hash = hashes[k]
- 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()
- local hashes = instance.hashes
- for i=1,#hashes do
- resolvers.generatedatabase(hashes[i].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"))
-
---~ local l_forbidden = lpeg.S("~`!#$%^&*()={}[]:;\"\'||\\/<>,?\n\r\t")
---~ local l_confusing = lpeg.P(" ")
---~ local l_character = lpeg.patterns.utf8
---~ local l_dangerous = lpeg.P(".")
-
---~ local l_normal = (l_character - l_forbidden - l_confusing - l_dangerous) * (l_character - l_forbidden - l_confusing^2)^0 * lpeg.P(-1)
---~ ----- l_normal = l_normal * lpeg.Cc(true) + lpeg.Cc(false)
-
---~ local function test(str)
---~ print(str,lpeg.match(l_normal,str))
---~ end
---~ test("ヒラギノ明朝 Pro W3")
---~ test("..ヒラギノ明朝 Pro W3")
---~ test(":ヒラギノ明朝 Pro W3;")
---~ test("ヒラギノ明朝 /Pro W3;")
---~ test("ヒラギノ明朝 Pro W3")
-
-function resolvers.generators.tex(specification)
- local tag = specification
- if trace_locating 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 lpegmatch(weird,name) then
- -- if lpegmatch(l_normal,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_locating 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.
-
---~ local checkedsplit = string.checkedsplit
-
-local cache = { }
-
-local splitter = lpeg.Ct(lpeg.splitat(lpeg.S(os.type == "windows" and ";" or ":;")))
-
-local function split_kpse_path(str) -- beware, this can be either a path or a {specification}
- local found = cache[str]
- if not found then
- if str == "" then
- found = { }
- else
- str = gsub(str,"\\","/")
---~ local split = (find(str,";") and checkedsplit(str,";")) or checkedsplit(str,io.pathseparator)
-local split = lpegmatch(splitter,str)
- found = { }
- for i=1,#split do
- local s = split[i]
- if not find(s,"^{*unset}*") then
- found[#found+1] = s
- end
- end
- if trace_expansions then
- logs.report("fileio","splitting path specification '%s'",str)
- for k=1,#found do
- logs.report("fileio","% 4i: %s",k,found[k])
- end
- end
- cache[str] = found
- end
- end
- return found
-end
-
-resolvers.split_kpse_path = split_kpse_path
-
-function resolvers.splitconfig()
- for i=1,#instance do
- local c = instance[i]
- for k,v in next, c do
- if type(v) == 'string' then
- local t = split_kpse_path(v)
- if #t > 1 then
- c[k] = t
- end
- end
- end
- end
-end
-
-function resolvers.joinconfig()
- local order = instance.order
- for i=1,#order do
- local c = order[i]
- for k,v in next, c do -- indexed?
- 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 split_kpse_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, p = { }, { }, split_kpse_path(v)
- for kk=1,#p do
- local vv = p[kk]
- 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
- local sortedfiles = sortedkeys(files)
- for i=1,#sortedfiles do
- local k = sortedfiles[i]
- local fk = files[k]
- if type(fk) == 'table' then
- t[#t+1] = "\t['" .. k .. "']={"
- local sortedfk = sortedkeys(fk)
- for j=1,#sortedfk do
- local kk = sortedfk[j]
- 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
-
-local data_state = { }
-
-function resolvers.data_state()
- return data_state or { }
-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_locating 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,
- uuid = os.uuid(),
- }
- local ok = io.savedata(luaname,resolvers.serialize(data))
- if ok then
- if trace_locating 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_locating then
- logs.report("fileio","'%s' compiled to '%s'",dataname,lucname)
- end
- else
- if trace_locating then
- logs.report("fileio","compiling failed for '%s', deleting file '%s'",dataname,lucname)
- end
- os.remove(lucname)
- end
- elseif trace_locating 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
- data_state[#data_state+1] = data.uuid
- if trace_locating then
- logs.report("fileio","loading '%s' for '%s' from '%s'",dataname,pathname,filename)
- end
- instance[dataname][pathname] = data.content
- else
- if trace_locating then
- logs.report("fileio","skipping '%s' for '%s' from '%s'",dataname,pathname,filename)
- end
- instance[dataname][pathname] = { }
- instance.loaderror = true
- end
- elseif trace_locating 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()
- local luafiles = instance.luafiles
- for i=1,#luafiles do
- local cnf = luafiles[i]
- 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_locating 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_locating then
- logs.report("fileio","skipping configuration file '%s'",filename)
- end
- instance['setup'][pathname] = { }
- instance.loaderror = true
- end
- elseif trace_locating 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
- local cnffiles = instance.cnffiles
- for i=1,#cnffiles do
- local cnf = cnffiles[i]
- 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 { } -- ep ?
- 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(tmp)
- else
- return resolvers.expanded_path_list(str)
- 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","file '%s' is readable",name)
- else
- logs.report("fileio","file '%s' is not readable", 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","checking name '%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","deep checking '%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","no match in '%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)
- -- 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","remembering file '%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","file '%s' found directly",filename)
- end
- instance.found[stamp] = { filename }
- return { filename }
- end
- end
- if find(filename,'%*') then
- if trace_locating then
- logs.report("fileio","checking 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 name '%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 = gsub(filename .. "$","([%.%-])","%%%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
- --
- if basename ~= filename then
- 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 find(rr,pattern) then
- result[#result+1], ok = rr, true
- end
- 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 find(ff,pattern) then
- -- result[#result+1], ok = ff, true
- -- end
- -- end
- -- end
- end
- if not ok and trace_locating then
- logs.report("fileio","qualified name '%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","checking filename '%s', filetype '%s', wanted files '%s'",filename, filetype or '?',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 dirlist = { }
- if filelist then
- for i=1,#filelist do
- dirlist[i] = file.dirname(filelist[i][2]) .. "/"
- end
- end
- if trace_detail then
- logs.report("fileio","checking filename '%s'",filename)
- end
- -- a bit messy ... esp the doscan setting here
- local doscan
- for k=1,#pathlist do
- local path = pathlist[k]
- if find(path,"^!!") then doscan = false else doscan = true end
- local pathname = gsub(path,"^!+", '')
- done = false
- -- using file list
- if filelist then
- local expression
- -- compare list entries with permitted pattern -- /xx /xx//
- if not find(pathname,"/$") then
- expression = pathname .. "/"
- else
- expression = pathname
- end
- expression = gsub(expression,"([%-%.])","%%%1") -- this also influences
- expression = gsub(expression,"//+$", '/.*') -- later usage of pathname
- expression = gsub(expression,"//", '/.-/') -- not ok for /// but harmless
- expression = "^" .. expression .. "$"
- if trace_detail then
- logs.report("fileio","using pattern '%s' for path '%s'",expression,pathname)
- end
- for k=1,#filelist do
- local fl = filelist[k]
- local f = fl[2]
- local d = dirlist[k]
- if find(d,expression) then
- --- todo, test for readable
- result[#result+1] = fl[3]
- resolvers.register_in_trees(f) -- for tracing used files
- done = true
- if instance.allresults then
- if trace_detail then
- logs.report("fileio","match in hash for file '%s' on path '%s', continue scanning",f,d)
- end
- else
- if trace_detail then
- logs.report("fileio","match in hash for file '%s' on path '%s', quit scanning",f,d)
- end
- break
- end
- elseif trace_detail then
- logs.report("fileio","no match in hash for file '%s' on path '%s'",f,d)
- 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 '%s' by scanning",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] or { }
- 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() -- will become the new method
- resolvers.expand_variables()
- resolvers.load_cnf() -- will be skipped when we have a lua file
- 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_locating then
- logs.report("fileio",str) -- has already verbose
- else
- print(str)
- end
- end
- if trace_locating then
- report('') -- ?
- end
- for f=1,#files do
- local file = files[f]
- local result = command(file,filetype,mustexist)
- if type(result) == 'string' then
- report(result)
- else
- for i=1,#result do
- report(result[i]) -- could be unpack
- 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 next, t do -- indexed?
- s[#s+1] = k .. "=" .. tostring(v)
- end
- return concat(s, sep or " | ")
-end
-
-function resolvers.methodhandler(what, filename, filetype) -- ...
- filename = file.collapse_path(filename)
- 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)
- local pathlist = resolvers.expanded_path_list(name)
- for i=1,#pathlist do
- func("^"..resolvers.clean_path(pathlist[i]))
- end
-end
-
-function resolvers.do_with_var(name,func)
- func(expanded_var(name))
-end
-
-function resolvers.with_files(pattern,handle)
- local hashes = instance.hashes
- for i=1,#hashes do
- local hash = hashes[i]
- 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 next, v do -- indexed
- handle(blobtype,blobpath,vv,k)
- end
- end
- end
- end
- end
- end
- end
-end
-
-function resolvers.locate_format(name)
- local barename, fmtname = gsub(name,"%.%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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
---[[ldx--
-<p>This module deals with caching data. It sets up the paths and
-implements loaders and savers for tables. Best is to set the
-following variable. When not set, the usual paths will be
-checked. Personally I prefer the (users) temporary path.</p>
-
-</code>
-TEXMFCACHE=$TMP;$TEMP;$TMPDIR;$TEMPDIR;$HOME;$TEXMFVAR;$VARTEXMF;.
-</code>
-
-<p>Currently we do no locking when we write files. This is no real
-problem because most caching involves fonts and the chance of them
-being written at the same time is small. We also need to extend
-luatools with a recache feature.</p>
---ldx]]--
-
-local format, lower, gsub = string.format, string.lower, string.gsub
-
-local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end) -- not used yet
-
-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)
- local dirs = { ... }
- if #dirs > 0 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
- loader = loader()
- collectgarbage("step")
- 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
- data.cache_uuid = os.uuid()
- 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.mkiv",
- 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.mkiv",
- 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.mkiv",
- 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)
-
---[[ldx--
-<p>Once we found ourselves defining similar cache constructs
-several times, containers were introduced. Containers are used
-to collect tables in memory and reuse them when possible based
-on (unique) hashes (to be provided by the calling function).</p>
-
-<p>Caching to disk is disabled by default. Version numbers are
-stored in the saved table which makes it possible to change the
-table structures without bothering about the disk cache.</p>
-
-<p>Examples of usage can be found in the font related code.</p>
---ldx]]--
-
-containers = containers or { }
-
-containers.usecache = true
-
-local function report(container,tag,name)
- if trace_cache or trace_containers then
- logs.report(format("%s cache",container.subcategory),"%s: %s",tag,name or 'invalid')
- end
-end
-
-local allocated = { }
-
--- tracing
-
-function containers.define(category, subcategory, version, enabled)
- return function()
- if category and subcategory then
- local c = allocated[category]
- if not c then
- c = { }
- allocated[category] = c
- end
- local s = c[subcategory]
- if not s then
- s = {
- category = category,
- subcategory = subcategory,
- storage = { },
- enabled = enabled,
- version = version or 1.000,
- trace = false,
- path = caches and caches.setpath and caches.setpath(category,subcategory),
- }
- c[subcategory] = s
- end
- return s
- else
- return nil
- end
- end
-end
-
-function containers.is_usable(container, name)
- return container.enabled and caches and caches.iswritable(container.path, name)
-end
-
-function containers.is_valid(container, name)
- if name and name ~= "" then
- local storage = container.storage[name]
- return storage and 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.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local format, lower, gsub, find = string.format, string.lower, string.gsub, string.find
-
-local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v 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 (not mountpaths or #mountpaths == 0) and usecache then
- mountpaths = { caches.setpath("mount") }
- end
- if mountpaths and #mountpaths > 0 then
- statistics.starttiming(resolvers.instance)
- for k=1,#mountpaths do
- local root = mountpaths[k]
- local f = io.open(root.."/url.tmi")
- if f then
- for line in f:lines() do
- if line then
- if find(line,"^[%%#%-]") then -- or %W
- -- skip
- elseif find(line,"^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")
- local luvbanner = luv.enginebanner or "?"
- if luvbanner ~= enginebanner then
- return string.format("engine mismatch (luv:%s <> bin:%s)",luvbanner,enginebanner)
- end
- local luvhash = luv.sourcehash or "?"
- if luvhash ~= sourcehash then
- return string.format("source mismatch (luv:%s <> bin:%s)",luvhash,sourcehash)
- end
- else
- return "invalid status file"
- end
- else
- return "missing status file"
- end
- end
- return true
-end
-
-
-end -- of closure
-
-do -- create closure to overcome 200 locals limit
-
-if not modules then modules = { } end modules ['luat-kps'] = {
- version = 1.001,
- comment = "companion to luatools.lua",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
---[[ldx--
-<p>This file is used when we want the input handlers to behave like
-<type>kpsewhich</type>. What to do with the following:</p>
-
-<typing>
-{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c}
-$SELFAUTOLOC : /usr/tex/bin/platform
-$SELFAUTODIR : /usr/tex/bin
-$SELFAUTOPARENT : /usr/tex
-</typing>
-
-<p>How about just forgetting about them?</p>
---ldx]]--
-
-local suffixes = resolvers.suffixes
-local formats = resolvers.formats
-
-suffixes['gf'] = { '<resolution>gf' }
-suffixes['pk'] = { '<resolution>pk' }
-suffixes['base'] = { 'base' }
-suffixes['bib'] = { 'bib' }
-suffixes['bst'] = { 'bst' }
-suffixes['cnf'] = { 'cnf' }
-suffixes['mem'] = { 'mem' }
-suffixes['mf'] = { 'mf' }
-suffixes['mfpool'] = { 'pool' }
-suffixes['mft'] = { 'mft' }
-suffixes['mppool'] = { 'pool' }
-suffixes['graphic/figure'] = { 'eps', 'epsi' }
-suffixes['texpool'] = { 'pool' }
-suffixes['PostScript header'] = { 'pro' }
-suffixes['ist'] = { 'ist' }
-suffixes['web'] = { 'web', 'ch' }
-suffixes['cweb'] = { 'w', 'web', 'ch' }
-suffixes['cmap files'] = { 'cmap' }
-suffixes['lig files'] = { 'lig' }
-suffixes['bitmap font'] = { }
-suffixes['MetaPost support'] = { }
-suffixes['TeX system documentation'] = { }
-suffixes['TeX system sources'] = { }
-suffixes['dvips config'] = { }
-suffixes['type42 fonts'] = { }
-suffixes['web2c files'] = { }
-suffixes['other text files'] = { }
-suffixes['other binary files'] = { }
-suffixes['opentype fonts'] = { 'otf' }
-
-suffixes['fmt'] = { 'fmt' }
-suffixes['texmfscripts'] = { 'rb','lua','py','pl' }
-
-suffixes['pdftex config'] = { }
-suffixes['Troff fonts'] = { }
-
-suffixes['ls-R'] = { }
-
---[[ldx--
-<p>If you wondered abou tsome of the previous mappings, how about
-the next bunch:</p>
---ldx]]--
-
-formats['bib'] = ''
-formats['bst'] = ''
-formats['mft'] = ''
-formats['ist'] = ''
-formats['web'] = ''
-formats['cweb'] = ''
-formats['MetaPost support'] = ''
-formats['TeX system documentation'] = ''
-formats['TeX system sources'] = ''
-formats['Troff fonts'] = ''
-formats['dvips config'] = ''
-formats['graphic/figure'] = ''
-formats['ls-R'] = ''
-formats['other text files'] = ''
-formats['other binary files'] = ''
-
-formats['gf'] = ''
-formats['pk'] = ''
-formats['base'] = 'MFBASES'
-formats['cnf'] = ''
-formats['mem'] = 'MPMEMS'
-formats['mf'] = 'MFINPUTS'
-formats['mfpool'] = 'MFPOOL'
-formats['mppool'] = 'MPPOOL'
-formats['texpool'] = 'TEXPOOL'
-formats['PostScript header'] = 'TEXPSHEADERS'
-formats['cmap files'] = 'CMAPFONTS'
-formats['type42 fonts'] = 'T42FONTS'
-formats['web2c files'] = 'WEB2C'
-formats['pdftex config'] = 'PDFTEXCONFIG'
-formats['texmfscripts'] = 'TEXMFSCRIPTS'
-formats['bitmap font'] = ''
-formats['lig files'] = 'LIGFONTS'
-
-
-end -- of closure
-
-do -- create closure to overcome 200 locals limit
-
-if not modules then modules = { } end modules ['data-aux'] = {
- version = 1.001,
- comment = "companion to luat-lib.mkiv",
- 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_locating = false trackers.register("resolvers.locating", function(v) trace_locating = 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_locating 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_locating 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_locating then
- logs.report("fileio","checking new script %s", newscript)
- end
- if oldscript == newscript then
- if trace_locating then
- logs.report("fileio","old and new script are the same")
- end
- elseif not find(newscript,scriptpath) then
- if trace_locating 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_locating then
- logs.report("fileio","invalid new script name")
- end
- else
- local newdata = io.loaddata(newscript)
- if newdata then
- if trace_locating then
- logs.report("fileio","old script content replaced by new content")
- end
- io.savedata(oldscript,newdata)
- break
- elseif trace_locating 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.mkiv",
- 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
- local sorted = table.sortedkeys(list)
- for i=1,#sorted do
- local key = sorted[i]
- 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
- local sorted = table.sortedkeys(instance.kpsevars)
- for i=1,#sorted do
- local key = sorted[i]
- if not instance.pattern or (instance.pattern=="") or find(key,instance.pattern) then
- report(format("%s\n",key))
- local order = instance.order
- for i=1,#order do
- local str = order[i][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',
- 'l-aux.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.32",environment.arguments["verbose"] or false)
-
-local instance = resolvers.reset()
-
-resolvers.defaultlibs = { -- not all are needed (this will become: context.lus (lua spec)
- '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
-
-local trackspec = environment.argument("trackers") or environment.argument("track")
-
-if trackspec then
- trackers.enable(trackspec)
-end
-
-runners = runners or { }
-messages = messages or { }
-
-messages.no_ini_file = [[
-There is no lua initialization file found. This file can be forced by the
-"--progname" directive, or specified with "--luaname", or it is derived
-automatically from the formatname (aka jobname). It may be that you have
-to regenerate the file database using "luatools --generate".
-]]
-
-messages.help = [[
---generate generate file database
---variables show configuration variables
---expansions show expanded variables
---configurations show configuration order
---expand-braces expand complex variable
---expand-path expand variable (resolve paths)
---expand-var expand variable (resolve references)
---show-path show path expansion of ...
---var-value report value of variable
---find-file report file location
---find-path report path of file
---make or --ini make luatex format
---run or --fmt= run luatex format
---luafile=str lua inifile (default is <progname>.lua)
---lualibs=list libraries to assemble (optional when --compile)
---compile assemble and compile lua inifile
---verbose give a bit more info
---all show all found files
---sort sort cached data
---engine=str target engine
---progname=str format or backend
---pattern=str filter variables
---trackers=list enable given trackers
-]]
-
-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
- local what = { instance.luaname, instance.progname, barename }
- for k=1,#what do
- local v = string.gsub(what[k]..".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 i=1,#mp do
- local name = mp[i]
- 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/mptopdf.exe b/scripts/context/stubs/mswin/mptopdf.exe
new file mode 100644
index 000000000..2d45f2749
--- /dev/null
+++ b/scripts/context/stubs/mswin/mptopdf.exe
Binary files differ
diff --git a/scripts/context/stubs/unix/mptopdf b/scripts/context/stubs/unix/mptopdf
new file mode 100644
index 000000000..c17b483be
--- /dev/null
+++ b/scripts/context/stubs/unix/mptopdf
@@ -0,0 +1,2 @@
+#!/bin/sh
+mtxrun --script base "$@"
diff --git a/tex/context/base/back-ini.lua b/tex/context/base/back-ini.lua
index 243e3fbd5..655500055 100644
--- a/tex/context/base/back-ini.lua
+++ b/tex/context/base/back-ini.lua
@@ -8,7 +8,9 @@ if not modules then modules = { } end modules ['back-ini'] = {
backends = backends or { }
-local trace_backend = false local function nothing() return nil end
+local trace_backend = false
+
+local function nothing() return nil end
local report_backends = logs.new("backends")
@@ -32,6 +34,8 @@ backends.nodeinjections = {
reference = nothing,
destination = nothing,
+ addtags = nothing,
+
}
backends.codeinjections = {
@@ -83,6 +87,13 @@ backends.codeinjections = {
setfigurecolorspace = nothing,
setfigurealternative = nothing,
+ enabletags = nothing,
+ maptag = nothing,
+ mapping = nothing, -- returns table
+
+ mergereferences = nothing,
+ mergelayers = nothing,
+
}
backends.registrations = {
diff --git a/tex/context/base/back-pdf.lua b/tex/context/base/back-pdf.lua
index 323d23a65..d43bdb701 100644
--- a/tex/context/base/back-pdf.lua
+++ b/tex/context/base/back-pdf.lua
@@ -31,18 +31,16 @@ local registrations = backends.pdf.registrations
local pdfliteral, register = nodes.pdfliteral, nodes.register
-local pdfconstant = lpdf.constant
-local pdfstring = lpdf.string
-local pdfdictionary = lpdf.dictionary
-local pdfarray = lpdf.array
-local pdfreference = lpdf.reference
-local pdfverbose = lpdf.verbose
-local pdfflushobject = lpdf.flushobject
-local pdfreserveobject = lpdf.reserveobject
-local pdfannotation = nodes.pdfannotation
-
-local pdfreserveobj = pdf.reserveobj
-local pdfimmediateobj = pdf.immediateobj
+local pdfconstant = lpdf.constant
+local pdfstring = lpdf.string
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfreference = lpdf.reference
+local pdfverbose = lpdf.verbose
+local pdfflushobject = lpdf.flushobject
+local pdfimmediateobject = lpdf.immediateobject
+
+local pdfannotation_node = nodes.pdfannotation
function nodeinjections.rgbcolor(r,g,b)
return register(pdfliteral(format("%s %s %s rg %s %s %s RG",r,g,b,r,g,b)))
@@ -134,7 +132,7 @@ function codeinjections.insertmovie(specification)
Movie = moviedict,
A = controldict,
}
- node.write(pdfannotation(width,height,0,action()))
+ node.write(pdfannotation_node(width,height,0,action()))
end
function codeinjections.insertsound(specification)
@@ -154,7 +152,7 @@ function codeinjections.insertsound(specification)
Movie = sounddict,
A = controldict,
}
- node.write(pdfannotation(0,0,0,action()))
+ node.write(pdfannotation_node(0,0,0,action()))
end
end
@@ -197,14 +195,22 @@ local function registersomespotcolor(name,noffractions,names,p,colorspace,range,
Domain = { 0, 1 },
Range = range,
}
- local n = pdfimmediateobj("stream",format("{ %s }",funct),dictionary())
+ local n = pdfimmediateobject("stream",format("{ %s }",funct),dictionary())
+
+--~ local n = pdfobject {
+--~ type = "stream",
+--~ immediate = true,
+--~ string = format("{ %s }",funct),
+--~ attr = dictionary(),
+--~ }
+
local array = pdfarray {
pdf_separation,
pdfconstant(spotcolornames[name] or name),
colorspace,
pdfreference(n),
}
- local m = pdfimmediateobj(tostring(array))
+ local m = pdfimmediateobject(tostring(array))
local mr = pdfreference(m)
spotcolorhash[name] = m
documentcolorspaces[name] = mr
@@ -222,14 +228,14 @@ local function registersomespotcolor(name,noffractions,names,p,colorspace,range,
Domain = domain,
Range = range,
}
- local n = pdfimmediateobj("stream",format("{ %s %s }",rep("pop ",noffractions),funct),dictionary())
+ local n = pdfimmediateobject("stream",format("{ %s %s }",rep("pop ",noffractions),funct),dictionary())
local array = pdfarray {
pdf_device_n,
cnames,
colorspace,
pdfreference(n),
}
- local m = pdfimmediateobj(tostring(array))
+ local m = pdfimmediateobject(tostring(array))
local mr = pdfreference(m)
spotcolorhash[name] = m
documentcolorspaces[name] = mr
@@ -256,7 +262,7 @@ local function registersomeindexcolor(name,noffractions,names,p,colorspace,range
Domain = domain,
Range = range,
}
- local n = pdfimmediateobj("stream",format("{ %s %s }",rep("exch pop ",noffractions),funct),dictionary()) -- exch pop
+ local n = pdfimmediateobject("stream",format("{ %s %s }",rep("exch pop ",noffractions),funct),dictionary()) -- exch pop
local a = pdfarray {
pdf_device_n,
cnames,
@@ -280,7 +286,7 @@ local function registersomeindexcolor(name,noffractions,names,p,colorspace,range
vector[#vector+1] = concat(set)
end
vector = pdfverbose { "<", concat(vector, " "), ">" }
- local n = pdfimmediateobj(tostring(pdfarray{ pdf_indexed, a, 255, vector }))
+ local n = pdfimmediateobject(tostring(pdfarray{ pdf_indexed, a, 255, vector }))
lpdf.adddocumentcolorspace(format("%s_indexed",name),pdfreference(n))
return n
end
@@ -393,7 +399,7 @@ function registrations.transparency(n,a,t)
BM = transparencies[1],
AIS = false,
}
- local m = pdfimmediateobj(tostring(d))
+ local m = pdfimmediateobject(tostring(d))
local mr = pdfreference(m)
transparencyhash[0] = m
documenttransparencies[0] = mr
@@ -408,7 +414,7 @@ function registrations.transparency(n,a,t)
BM = transparencies[a] or transparencies[0],
AIS = false,
}
- local m = pdfimmediateobj(tostring(d))
+ local m = pdfimmediateobject(tostring(d))
local mr = pdfreference(m)
transparencyhash[n] = m
documenttransparencies[n] = mr
@@ -440,14 +446,14 @@ function codeinjections.setfigurealternative(data,figure)
if displayfigure then
-- figure.aform = true
img.immediatewrite(figure)
- local a = lpdf.array {
- lpdf.dictionary {
- Image = lpdf.reference(figure.objnum),
+ local a = pdfarray {
+ pdfdictionary {
+ Image = pdfreference(figure.objnum),
DefaultForPrinting = true,
}
}
- local d = lpdf.dictionary {
- Alternates = lpdf.reference(pdf.immediateobj(tostring(a))),
+ local d = pdfdictionary {
+ Alternates = pdfreference(pdfimmediateobject(tostring(a))),
}
displayfigure.attr = d()
return displayfigure, figures.current()
diff --git a/tex/context/base/back-pdf.mkiv b/tex/context/base/back-pdf.mkiv
index a10afd5b9..3cae2afd2 100644
--- a/tex/context/base/back-pdf.mkiv
+++ b/tex/context/base/back-pdf.mkiv
@@ -119,7 +119,7 @@
%D The following will move to the backend \LUA\ code:
\appendtoks \ctxlua{backends.codeinjections.finalizepage ()}\to \everybackendshipout % is immediate
-\appendtoks \ctxlua{backends.codeinjections.finalizedocument()}\to \everylastbackendshipout % is immediate
+%appendtoks \ctxlua{backends.codeinjections.finalizedocument()}\to \everylastbackendshipout % is immediate
%D Temporary hack, will be removed or improved or default.
diff --git a/tex/context/base/bibl-bib.mkiv b/tex/context/base/bibl-bib.mkiv
index 10abe5cb8..e4a92b3c0 100644
--- a/tex/context/base/bibl-bib.mkiv
+++ b/tex/context/base/bibl-bib.mkiv
@@ -627,7 +627,7 @@
\ifx\currentbibtexsessiontag\empty
% can't really happen
\else\ifx\currentbibtexcriterium\v!all
- \doplacepublicationindeed
+ \dotypesetbibtexpublication % was \doplacepublicationindeed
\else
\ctxlua{bibtex.hacks.doifalreadyplaced("\currentbibtexsessiontag")}
\donothing
diff --git a/tex/context/base/buff-ini.mkiv b/tex/context/base/buff-ini.mkiv
index 13f69554f..64bc66149 100644
--- a/tex/context/base/buff-ini.mkiv
+++ b/tex/context/base/buff-ini.mkiv
@@ -176,6 +176,9 @@
\def\thebuffernumber#1%
{\csname\??bu#1\c!number\endcsname}
+
+\def\thedefinedbuffer#1%
+ {def-\csname\??bu#1\c!number\endcsname}
\unexpanded\def\getbuffer
{\dodoubleempty\dogetbuffer}
@@ -199,13 +202,17 @@
\def\doprocessbufferverbatim
{\doinitializeverbatim
- \ctxlua{buffers.type("\currentbuffer","\typingparameter\c!strip")}}
+ \dostarttagged\t!verbatim\currentbuffer
+ \ctxlua{buffers.type("\currentbuffer","\typingparameter\c!strip")}%
+ \dostoptagged}
\def\doprocessbufferlinesverbatim#1#2#3%
{#2%
% todo, set up numbers
\doinitializeverbatim
+ \dostarttagged\t!verbatim\currentbuffer
\ctxlua{buffers.type("\currentbuffer","\typingparameter\c!strip")}
+ \dostoptagged
#3}
\def\doifelsebuffer#1%
diff --git a/tex/context/base/buff-ver.mkiv b/tex/context/base/buff-ver.mkiv
index cc8882ac6..59b484983 100644
--- a/tex/context/base/buff-ver.mkiv
+++ b/tex/context/base/buff-ver.mkiv
@@ -344,7 +344,9 @@
\def\dodotypeAA#1%
{\doinitializeverbatim
\def\obs{\obeyedspace}%
+ \dostarttagged\t!verbatim\currenttyping
\ctxlua{buffers.hooks.flush_inline(\!!bs\detokenize{#1}\!!es)}%
+ \dostoptagged
\egroup}
\def\dodotypeB#1%
@@ -356,7 +358,9 @@
\def\dodotypeBB#1%
{\doinitializeverbatim
+ \dostarttagged\t!verbatim\currenttyping
\ctxlua{buffers.visualizers.flush_nested(\!!bs\detokenize{#1}\!!es,false)}%
+ \dostoptagged
\egroup
\gobbleoneargument} % grab last >
@@ -370,7 +374,9 @@
\def\dodotypeCC#1%
{\doinitializeverbatim
\ifx\obeycharacters\setupprettytype % temp hack, we need a proper signal
+ \dostarttagged\t!verbatim\currenttyping
\ctxlua{buffers.hooks.flush_inline([\!!bs\detokenize{#1}\!!es,true)}%
+ \dostoptagged
\else
\def\obs{\obeyedspace}%
\ctxlua{buffers.visualizers.flush_nested(\!!bs\detokenize{#1}\!!es,true)}%
@@ -388,7 +394,9 @@
\def\dodotypeDD#1%
{\doinitializeverbatim
+ \dostarttagged\t!verbatim\currenttyping
\ctxlua{buffers.hooks.flush_inline(\!!bs\detokenize{#1}\!!es,true)}%
+ \dostoptagged
\egroup
\gobbleoneargument} % grab last >
@@ -634,7 +642,9 @@
\def\dotypefileverbatim
{\doinitializeverbatim
\beginofverbatimlines
+ \dostarttagged\t!verbatimblock\currenttyping
\ctxlua{buffers.typefile("\readfilename","\typingparameter\c!strip","\typingparameter\c!range")}%
+ \dostoptagged
\endofverbatimlines}
\def\dotypefilelinesverbatim#1#2%
@@ -645,7 +655,9 @@
{}
{\doinitializeverbatim
\beginofverbatimlines
+ \dostarttagged\t!verbatimblock\currenttyping
\ctxlua{buffers.type("_typing_","\typingparameter\c!strip","\typingparameter\c!range")}%
+ \dostoptagged
\endofverbatimlines
\csname#2\endcsname}}
diff --git a/tex/context/base/cont-new.tex b/tex/context/base/cont-new.tex
index a0eaec3bf..cae797270 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{2010.07.15 15:01}
+\newcontextversion{2010.07.30 11:35}
%D This file is loaded at runtime, thereby providing an
%D excellent place for hacks, patches, extensions and new
diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv
index 32bcfbe24..13e091ea8 100644
--- a/tex/context/base/context.mkiv
+++ b/tex/context/base/context.mkiv
@@ -167,6 +167,7 @@
\loadmarkfile{lxml-sor}
\loadmarkfile{strc-ini}
+\loadmarkfile{strc-tag}
\loadmarkfile{strc-doc}
\loadmarkfile{strc-mar}
\loadmarkfile{strc-prc}
@@ -328,6 +329,7 @@
\loadmarkfile{grph-trf}
\loadmarkfile{grph-inc}
\loadmarkfile{grph-fig}
+\loadmarkfile{grph-epd}
\loadmarkfile{pack-box}
\loadmarkfile{pack-bar}
diff --git a/tex/context/base/context.tex b/tex/context/base/context.tex
index 16f1f44e6..4abee1332 100644
--- a/tex/context/base/context.tex
+++ b/tex/context/base/context.tex
@@ -20,7 +20,7 @@
%D your styles an modules.
\edef\contextformat {\jobname}
-\edef\contextversion{2010.07.15 15:01}
+\edef\contextversion{2010.07.30 11:35}
%D For those who want to use this:
diff --git a/tex/context/base/core-mis.mkiv b/tex/context/base/core-mis.mkiv
index e2bd28bd5..6e159532f 100644
--- a/tex/context/base/core-mis.mkiv
+++ b/tex/context/base/core-mis.mkiv
@@ -706,11 +706,13 @@
\ifnum\subsentencelevel=\plusone
\dontleavehmode % was \leaveoutervmode
\fi
+ \dostarttagged\t!subsentence\empty
\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]%
+ \dostoptagged
\global\advance\subsentencelevel\minusone
\unskip
\kern\subsentencesignal\relax
@@ -741,6 +743,7 @@
\unexpanded\def\startsubsentence{\beginofsubsentence \prewordbreak\beginofsubsentencespacing}
\unexpanded\def\stopsubsentence {\endofsubsentencespacing\prewordbreak\endofsubsentence}
+\unexpanded\def\subsentence {\groupedcommand\startsubsentence\stopsubsentence}
%D \defineXMLenvironment [subsentence]
%D {|<|}
@@ -885,6 +888,7 @@
\unexpanded\def\startdelimitedtext[#1]%
{\bgroup
\pushdelimitedtext{#1}%
+ \dostarttagged\t!delimitedblock\currentdelimitedtext
\doifelse{\delimitedtextparameter\c!method}\s!font
{\def\dostopdelimitedtext
{\removeunwantedspaces\ignoredelimitedtext\c!right}%
@@ -895,39 +899,6 @@
\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\dostartdelimitedtextpar[#1]%
{\let\dostopdelimitedtext\dostopdelimitedtextpar
\doifsomething{\delimitedtextparameter\c!spacebefore}
@@ -978,6 +949,7 @@
\unexpanded\def\stopdelimitedtext
{\dostopdelimitedtext
+ \dostoptagged
\popdelimitedtext
\egroup}
@@ -1113,35 +1085,56 @@
\def\handlerightdelimitedtext#1%
{\dohandlerightdelimitedtext{#1}\relax}
+% \unexpanded\def\dodelimitedtextpar
+% {\dohandleleftdelimitedtext\c!left\relax
+% \groupedcommand
+% \donothing
+% {\dohandlerightdelimitedtext\c!right\removelastskip
+% \popdelimitedtext}}
+
\unexpanded\def\dodelimitedtextpar
- {\dohandleleftdelimitedtext\c!left\relax
- \groupedcommand
- \donothing
+ {\groupedcommand
+ {\dostarttagged\t!delimited\currentdelimitedtext % block?
+ \dohandleleftdelimitedtext\c!left\relax}
{\dohandlerightdelimitedtext\c!right\removelastskip
+ \dostoptagged
\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\doquoteddelimited
- {\dohandleleftdelimitedtext\c!left\relax
- \groupedcommand
- \donothing
+ {\groupedcommand
+ {\dostarttagged\t!delimited\currentdelimitedtext
+ \dohandleleftdelimitedtext\c!left\relax}
{\dohandlerightdelimitedtext\c!right
\removelastskip
+ \dostoptagged
\popdelimitedtext}}
\def\doattributeddelimited
{\groupedcommand
- {\dostartattributes{\??ci\currentdelimitedtext}\c!style\c!color}
+ {\dostarttagged\t!delimited\currentdelimitedtext
+ \dostartattributes{\??ci\currentdelimitedtext}\c!style\c!color}
{\dostopattributes
+ \dostoptagged
\popdelimitedtext}}
\def\dofontdrivendelimited
{\simplegroupedcommand
- {\languageparameter{\c!left\currentdelimitedtext}}
+ {\dostarttagged\t!delimited\currentdelimitedtext
+ \languageparameter{\c!left\currentdelimitedtext}}
{\languageparameter{\c!right\currentdelimitedtext}%
+ \dostoptagged
\popdelimitedtext}}
% testcase for nesting:
diff --git a/tex/context/base/core-sys.mkiv b/tex/context/base/core-sys.mkiv
index 649e5e65c..7b1f2825a 100644
--- a/tex/context/base/core-sys.mkiv
+++ b/tex/context/base/core-sys.mkiv
@@ -206,16 +206,20 @@
\setuvalue{#1}%
{\groupedcommand
{\getvalue{\??be#1\c!commands}%
+ \dostarttagged\t!construct{#1}%
\dostartattributes{\??be#1}\c!style\c!color}
{\dostopattributes
+ \dostoptagged
\getvalue{\??be#1\c!inbetween}}}%
\setvalue{\e!start#1}%
{\getvalue{\??be#1\c!before}%
\bgroup
\getvalue{\??be#1\c!commands}%
+ \dostarttagged\t!construct{#1}%
\dostartattributes{\??be#1}\c!style\c!color\empty}%
\setvalue{\e!stop#1}%
{\dostopattributes
+ \dostoptagged
\egroup
\getvalue{\??be#1\c!after}}}
diff --git a/tex/context/base/core-uti.lua b/tex/context/base/core-uti.lua
index 68efdcb0c..2a8f31364 100644
--- a/tex/context/base/core-uti.lua
+++ b/tex/context/base/core-uti.lua
@@ -72,8 +72,10 @@ local function initializer()
if not r then
r = math.random()
math.setrandomseedi(r,"initialize")
+ report_jobcontrol("initializing randomizer with %s",r)
else
math.setrandomseedi(r,"previous run")
+ report_jobcontrol("resuming randomizer with %s",r)
end
jobvariables.tobesaved.randomseed = r
for cs, value in next, jobvariables.collected do
diff --git a/tex/context/base/core-uti.mkiv b/tex/context/base/core-uti.mkiv
index 352093ff5..d16d33ce0 100644
--- a/tex/context/base/core-uti.mkiv
+++ b/tex/context/base/core-uti.mkiv
@@ -26,10 +26,15 @@
job.comment("format: \contextformat")
job.comment("stamp: \contextversion")
job.comment("escape: \!!bs\space...\space\!!es")
- job.initialize("\jobname.tuc","\jobname.tua")
}%
\to \everystarttext
+\appendtoks
+ \ctxlua {
+ job.initialize("\jobname.tuc","\jobname.tua")
+ }%
+\to \everyjob
+
\def\notuccompression{\ctxlua{job.pack=false}}
%D Some styles might use these use these commands:
diff --git a/tex/context/base/data-kps.lua b/tex/context/base/data-kps.lua
deleted file mode 100644
index 09d502409..000000000
--- a/tex/context/base/data-kps.lua
+++ /dev/null
@@ -1,101 +0,0 @@
-if not modules then modules = { } end modules ['luat-kps'] = {
- version = 1.001,
- comment = "companion to luatools.lua",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
---[[ldx--
-<p>This file is used when we want the input handlers to behave like
-<type>kpsewhich</type>. What to do with the following:</p>
-
-<typing>
-{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c}
-$SELFAUTOLOC : /usr/tex/bin/platform
-$SELFAUTODIR : /usr/tex/bin
-$SELFAUTOPARENT : /usr/tex
-</typing>
-
-<p>How about just forgetting about them?</p>
---ldx]]--
-
-local suffixes = resolvers.suffixes
-local formats = resolvers.formats
-
-suffixes['gf'] = { '<resolution>gf' }
-suffixes['pk'] = { '<resolution>pk' }
-suffixes['base'] = { 'base' }
-suffixes['bib'] = { 'bib' }
-suffixes['bst'] = { 'bst' }
-suffixes['cnf'] = { 'cnf' }
-suffixes['mem'] = { 'mem' }
-suffixes['mf'] = { 'mf' }
-suffixes['mfpool'] = { 'pool' }
-suffixes['mft'] = { 'mft' }
-suffixes['mppool'] = { 'pool' }
-suffixes['graphic/figure'] = { 'eps', 'epsi' }
-suffixes['texpool'] = { 'pool' }
-suffixes['PostScript header'] = { 'pro' }
-suffixes['ist'] = { 'ist' }
-suffixes['web'] = { 'web', 'ch' }
-suffixes['cweb'] = { 'w', 'web', 'ch' }
-suffixes['cmap files'] = { 'cmap' }
-suffixes['lig files'] = { 'lig' }
-suffixes['bitmap font'] = { }
-suffixes['MetaPost support'] = { }
-suffixes['TeX system documentation'] = { }
-suffixes['TeX system sources'] = { }
-suffixes['dvips config'] = { }
-suffixes['type42 fonts'] = { }
-suffixes['web2c files'] = { }
-suffixes['other text files'] = { }
-suffixes['other binary files'] = { }
-suffixes['opentype fonts'] = { 'otf' }
-
-suffixes['fmt'] = { 'fmt' }
-suffixes['texmfscripts'] = { 'rb','lua','py','pl' }
-
-suffixes['pdftex config'] = { }
-suffixes['Troff fonts'] = { }
-
-suffixes['ls-R'] = { }
-
---[[ldx--
-<p>If you wondered abou tsome of the previous mappings, how about
-the next bunch:</p>
---ldx]]--
-
-formats['bib'] = ''
-formats['bst'] = ''
-formats['mft'] = ''
-formats['ist'] = ''
-formats['web'] = ''
-formats['cweb'] = ''
-formats['MetaPost support'] = ''
-formats['TeX system documentation'] = ''
-formats['TeX system sources'] = ''
-formats['Troff fonts'] = ''
-formats['dvips config'] = ''
-formats['graphic/figure'] = ''
-formats['ls-R'] = ''
-formats['other text files'] = ''
-formats['other binary files'] = ''
-
-formats['gf'] = ''
-formats['pk'] = ''
-formats['base'] = 'MFBASES'
-formats['cnf'] = ''
-formats['mem'] = 'MPMEMS'
-formats['mf'] = 'MFINPUTS'
-formats['mfpool'] = 'MFPOOL'
-formats['mppool'] = 'MPPOOL'
-formats['texpool'] = 'TEXPOOL'
-formats['PostScript header'] = 'TEXPSHEADERS'
-formats['cmap files'] = 'CMAPFONTS'
-formats['type42 fonts'] = 'T42FONTS'
-formats['web2c files'] = 'WEB2C'
-formats['pdftex config'] = 'PDFTEXCONFIG'
-formats['texmfscripts'] = 'TEXMFSCRIPTS'
-formats['bitmap font'] = ''
-formats['lig files'] = 'LIGFONTS'
diff --git a/tex/context/base/font-ctx.lua b/tex/context/base/font-ctx.lua
index 85577f4a7..5e4d598f1 100644
--- a/tex/context/base/font-ctx.lua
+++ b/tex/context/base/font-ctx.lua
@@ -336,7 +336,8 @@ local n = 0
-- we can also move rscale to here (more consistent)
-function define.command_2(global,cs,str,size,classfeatures,fontfeatures,classfallbacks,fontfallbacks,mathsize,textsize,relativeid)
+function define.command_2(global,cs,str,size,classfeatures,fontfeatures,classfallbacks,fontfallbacks,
+ mathsize,textsize,relativeid,classgoodies,goodies)
if trace_defining then
report_define("memory usage before: %s",statistics.memused())
end
@@ -355,6 +356,7 @@ function define.command_2(global,cs,str,size,classfeatures,fontfeatures,classfal
specification.sub = (sub and sub ~= "" and sub) or specification.sub
specification.mathsize = mathsize
specification.textsize = textsize
+ specification.goodies = goodies
if detail and detail ~= "" then
specification.method, specification.detail = method or "*", detail
elseif specification.detail and specification.detail ~= "" then
@@ -375,7 +377,8 @@ function define.command_2(global,cs,str,size,classfeatures,fontfeatures,classfal
texsetcount("global","lastfontid",-1)
elseif type(tfmdata) == "number" then
if trace_defining then
- report_define("reusing %s with id %s as \\%s (features: %s/%s, fallbacks: %s/%s)",name,tfmdata,cs,classfeatures,fontfeatures,classfallbacks,fontfallbacks)
+ report_define("reusing %s with id %s as \\%s (features: %s/%s, fallbacks: %s/%s, goodies: %s/%s)",
+ name,tfmdata,cs,classfeatures,fontfeatures,classfallbacks,fontfallbacks,classgoodies,goodies)
end
tex.definefont(global,cs,tfmdata)
-- resolved (when designsize is used):
diff --git a/tex/context/base/font-def.lua b/tex/context/base/font-def.lua
index a35c4856f..ea5b69a6b 100644
--- a/tex/context/base/font-def.lua
+++ b/tex/context/base/font-def.lua
@@ -290,6 +290,15 @@ function define.resolve(specification)
else
specification.forced = specification.forced
end
+ -- for the moment here (goodies eset outside features)
+ local goodies = specification.goodies
+ if goodies and goodies ~= "" then
+ local normalgoodies = specification.features.normal.goodies
+ if not normalgoodies or normalgoodies == "" then
+ specification.features.normal.goodies = goodies
+ end
+ end
+ --
specification.hash = lower(specification.name .. ' @ ' .. tfm.hash_features(specification))
if specification.sub and specification.sub ~= "" then
specification.hash = specification.sub .. ' @ ' .. specification.hash
diff --git a/tex/context/base/font-gds.lua b/tex/context/base/font-gds.lua
index e17a47ca2..f0d52974a 100644
--- a/tex/context/base/font-gds.lua
+++ b/tex/context/base/font-gds.lua
@@ -297,3 +297,4 @@ fonts.goodies.register("mathematics", initialize)
-- tex/fonts/data/foundry/collection
--
-- see lfg files in distribution
+
diff --git a/tex/context/base/font-ini.lua b/tex/context/base/font-ini.lua
index 296af06e1..94522130c 100644
--- a/tex/context/base/font-ini.lua
+++ b/tex/context/base/font-ini.lua
@@ -26,6 +26,8 @@ fontloader.totable = fontloader.to_table
fonts = fonts or { }
+-- we will also have des and fam hashes
+
fonts.ids = fonts.ids or { } fonts.identifiers = fonts.ids -- aka fontdata
fonts.chr = fonts.chr or { } fonts.characters = fonts.chr -- aka chardata
fonts.qua = fonts.qua or { } fonts.quads = fonts.qua -- aka quaddata
diff --git a/tex/context/base/font-ini.mkiv b/tex/context/base/font-ini.mkiv
index 2df094330..e08f5bdd9 100644
--- a/tex/context/base/font-ini.mkiv
+++ b/tex/context/base/font-ini.mkiv
@@ -74,6 +74,7 @@
\registerctxluafile{font-ota}{1.001} % otf analyzers
\registerctxluafile{font-otp}{1.001} % otf pack
\registerctxluafile{font-otc}{1.001} % otf context
+\registerctxluafile{font-oth}{1.001} % otf helpers
\registerctxluafile{font-vf} {1.001}
\registerctxluafile{font-def}{1.001}
\registerctxluafile{font-ctx}{1.001}
@@ -734,7 +735,9 @@
"\@@fontfallbacks",
0\currentmathsize,
\number\dimexpr\textface\relax,
- "\relativefontid" % experiment
+ "\relativefontid", % experiment
+ "\@@fontclassgoodies", % experiment (not yet used)
+ "\@@fontgoodies" % experiment
)}%
\edef\somefontspec{at \somefontsize}% we need the resolved designsize (for fallbacks)
\expandafter\let\expandafter\lastrawfontcall\csname#2\endcsname
@@ -742,7 +745,8 @@
\def\updatefontclassparameters
{\edef\@@fontclassfeatures {\ifcsname\fontclass\fontstyle\s!features \endcsname\csname\fontclass\fontstyle\s!features \endcsname\fi}%
- \edef\@@fontclassfallbacks{\ifcsname\fontclass\fontstyle\s!fallbacks\endcsname\csname\fontclass\fontstyle\s!fallbacks\endcsname\fi}}
+ \edef\@@fontclassfallbacks{\ifcsname\fontclass\fontstyle\s!fallbacks\endcsname\csname\fontclass\fontstyle\s!fallbacks\endcsname\fi}%
+ \edef\@@fontclassgoodies {\ifcsname\fontclass\fontstyle\s!goodies \endcsname\csname\fontclass\fontstyle\s!goodies \endcsname\fi}}
% resolve
@@ -760,6 +764,13 @@
\ifcsname\??ff #1\endcsname\@EA \@@thefallbacksyes\csname\??ff #1\endcsname\else
\let \@@fontfallbacks \empty \fi\fi\fi\fi}
+\def\@@thegoodiesyes#1%
+ {\ifcsname\??ff\fontclass#1\s!goodies \endcsname\@EA\let\@EA\@@fontgoodies \csname\??ff\fontclass#1\s!goodies \endcsname\else
+ \ifcsname\??ff #1\s!goodies \endcsname\@EA\let\@EA\@@fontgoodies \csname\??ff #1\s!goodies \endcsname\else
+ \ifcsname\??ff\fontclass #1\endcsname\@EA \@@thegoodiesyes \csname\??ff\fontclass #1\endcsname\else
+ \ifcsname\??ff #1\endcsname\@EA \@@thegoodiesyes \csname\??ff #1\endcsname\else
+ \let \@@fontgoodies \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
@@ -770,13 +781,20 @@
\ifcsname\??ff #1\endcsname\@EA \@@thefallbacksnop\csname\??ff #1\endcsname\else
\let \@@fontfallbacks \empty \fi\fi}
+\def\@@thegoodiesnop#1%
+ {\ifcsname\??ff#1\s!goodies \endcsname\@EA\let\@EA\@@fontgoodies \csname\??ff#1\s!goodies \endcsname\else
+ \ifcsname\??ff #1\endcsname\@EA \@@thegoodiesnop \csname\??ff #1\endcsname\else
+ \let \@@fontgoodies \empty \fi\fi}
+
\def\updatefontparametersyes
{\@@thefeaturesyes \somefontname
- \@@thefallbacksyes\somefontname}
+ \@@thefallbacksyes\somefontname
+ \@@thegoodiesyes \somefontname}
\def\updatefontparametersnop
{\@@thefeaturesnop \somefontname
- \@@thefallbacksnop\somefontname}
+ \@@thefallbacksnop\somefontname
+ \@@thegoodiesnop \somefontname}
\def\updatefontparameters
{\ifx\fontclass\empty\updatefontparametersnop\else\updatefontparametersyes\fi}
@@ -786,6 +804,8 @@
\let\@@fontfallbacks\empty
\let\@@fontfeatures \empty
+\let\@@fontgoodies \empty
+
\let\@@hyphenchar \empty % todo, will go to encoding
%D This brings down maps processing from 466 to 309 seconds
@@ -972,19 +992,23 @@
\def\nonodefinefontsynonymnop
{\@EA\let\csname\??ff\@@fontname\s!features \endcsname\undefined
- \@EA\let\csname\??ff\@@fontname\s!fallbacks\endcsname\undefined}
+ \@EA\let\csname\??ff\@@fontname\s!fallbacks\endcsname\undefined
+ \@EA\let\csname\??ff\@@fontname\s!goodies \endcsname\undefined}
\def\nonodefinefontsynonymyes
{\fcglobal\@EA\let\csname\??ff\fontclass\@@fontname\s!features \endcsname\undefined
- \fcglobal\@EA\let\csname\??ff\fontclass\@@fontname\s!fallbacks\endcsname\undefined}
+ \fcglobal\@EA\let\csname\??ff\fontclass\@@fontname\s!fallbacks\endcsname\undefined
+ \fcglobal\@EA\let\csname\??ff\fontclass\@@fontname\s!goodies \endcsname\undefined}
\def\dodododefinefontsynonymnop
{\@EA\let\csname\??ff\@@fontname\s!features \endcsname\@@ff@@features
- \@EA\let\csname\??ff\@@fontname\s!fallbacks\endcsname\@@ff@@fallbacks}
+ \@EA\let\csname\??ff\@@fontname\s!fallbacks\endcsname\@@ff@@fallbacks
+ \@EA\let\csname\??ff\@@fontname\s!goodies \endcsname\@@ff@@goodies}
\def\dodododefinefontsynonymyes
{\fcglobal\@EA\let\csname\??ff\fontclass\@@fontname\s!features \endcsname\@@ff@@features
- \fcglobal\@EA\let\csname\??ff\fontclass\@@fontname\s!fallbacks\endcsname\@@ff@@fallbacks}
+ \fcglobal\@EA\let\csname\??ff\fontclass\@@fontname\s!fallbacks\endcsname\@@ff@@fallbacks
+ \fcglobal\@EA\let\csname\??ff\fontclass\@@fontname\s!goodies \endcsname\@@ff@@goodies}
\let\definefontfile\definefontsynonym % dedicated to Taco Hoekwater
@@ -2139,10 +2163,11 @@
\trycurrentfontclass{#1}%
\fi\fi\fi}
-\def\savefontclassparameters#1#2#3#4% #1=rm|ss|.. rscale features fallbacks
+\def\savefontclassparameters#1#2#3#4#5% #1=rm|ss|.. rscale features fallbacks goodies
{\setxvalue{\fontclass#1\s!rscale }{#2}%
\setxvalue{\fontclass#1\s!features }{#3}%
- \setxvalue{\fontclass#1\s!fallbacks}{#4}}
+ \setxvalue{\fontclass#1\s!fallbacks}{#4}%
+ \setxvalue{\fontclass#1\s!goodies }{#5}}
\settrue\autotypescripts
@@ -3756,24 +3781,43 @@
\definefontsize[\c!a] \definefontsize[\c!b]
\definefontsize[\c!c] \definefontsize[\c!d]
-\definealternativestyle [\v!mediaeval] [\os] []
-\definealternativestyle [\v!normal] [\tf] []
-\definealternativestyle [\v!bold] [\bf] []
-\definealternativestyle [\v!type] [\tt] []
-\definealternativestyle [\v!mono] [\tt] []
-\definealternativestyle [\v!slanted] [\sl] []
-\definealternativestyle [\v!italic] [\it] []
-\definealternativestyle [\v!boldslanted,\v!slantedbold] [\bs] []
-\definealternativestyle [\v!bolditalic,\v!italicbold] [\bi] []
-\definealternativestyle [\v!small,\v!smallnormal] [\tfx] []
-\definealternativestyle [\v!smallbold] [\bfx] []
-\definealternativestyle [\v!smalltype] [\ttx] []
-\definealternativestyle [\v!smallslanted] [\slx] []
-\definealternativestyle [\v!smallboldslanted,\v!smallslantedbold] [\bsx] []
-\definealternativestyle [\v!smallbolditalic,\v!smallitalicbold] [\bix] []
-
-\definealternativestyle [\v!sans,\v!sansserif] [\ss] []
-\definealternativestyle [\v!sansbold] [\ss\bf] []
+\definealternativestyle [\v!mediaeval] [\os] []
+\definealternativestyle [\v!normal] [\tf] []
+\definealternativestyle [\v!bold] [\bf] []
+\definealternativestyle [\v!type] [\tt] []
+\definealternativestyle [\v!mono] [\tt] []
+\definealternativestyle [\v!slanted] [\sl] []
+\definealternativestyle [\v!italic] [\it] []
+\definealternativestyle [\v!boldslanted,\v!slantedbold] [\bs] []
+\definealternativestyle [\v!bolditalic,\v!italicbold] [\bi] []
+
+% \definealternativestyle [\v!small,\v!smallnormal] [\tfx] []
+% \definealternativestyle [\v!smallbold] [\bfx] []
+% \definealternativestyle [\v!smalltype] [\ttx] []
+% \definealternativestyle [\v!smallslanted] [\slx] []
+% \definealternativestyle [\v!smallboldslanted,\v!smallslantedbold] [\bsx] []
+% \definealternativestyle [\v!smallbolditalic,\v!smallitalicbold] [\bix] []
+
+\definealternativestyle [\v!small,\v!smallnormal] [\setsmallbodyfont\tf] []
+\definealternativestyle [\v!smallbold] [\setsmallbodyfont\bf] []
+\definealternativestyle [\v!smalltype] [\setsmallbodyfont\tt] []
+\definealternativestyle [\v!smallslanted] [\setsmallbodyfont\sl] []
+\definealternativestyle [\v!smallboldslanted,\v!smallslantedbold] [\setsmallbodyfont\bs] []
+\definealternativestyle [\v!smallbolditalic,\v!smallitalicbold] [\setsmallbodyfont\bi] []
+
+\definealternativestyle [\v!bigger] [\setbigbodyfont \tf] []
+\definealternativestyle [\v!smaller] [\setsmallbodyfont\tf] []
+
+\definealternativestyle [\v!sans,\v!sansserif] [\ss] []
+\definealternativestyle [\v!sansbold] [\ss\bf] []
+
+%D We can go on and on and on:
+%D
+%D \starttyping
+%D \setupbodyfontenvironment[default][p=0.8,q=0.6]
+%D \definefontsize[p]
+%D \definefontsize[q]
+%D \stoptyping
%D Slow but handy:
diff --git a/tex/context/base/font-otb.lua b/tex/context/base/font-otb.lua
index 65933b240..f76e6686c 100644
--- a/tex/context/base/font-otb.lua
+++ b/tex/context/base/font-otb.lua
@@ -168,7 +168,7 @@ local function prepare_base_substitutions(tfmdata,kind,value) -- we can share so
if pv then
local upv = unicodes[pv]
if upv then
- if type(upv) == "table" then
+ if type(upv) == "table" then -- zero change that table
upv = upv[1]
end
if characters[upv] then
@@ -196,7 +196,7 @@ local function prepare_base_substitutions(tfmdata,kind,value) -- we can share so
if pc then
local upc = unicodes[pc]
if upc then
- if type(upc) == "table" then
+ if type(upc) == "table" then -- zero change that table
upc = upc[1]
end
if characters[upc] then
diff --git a/tex/context/base/font-oth.lua b/tex/context/base/font-oth.lua
new file mode 100644
index 000000000..62ff41c40
--- /dev/null
+++ b/tex/context/base/font-oth.lua
@@ -0,0 +1,45 @@
+if not modules then modules = { } end modules ['font-oth'] = {
+ version = 1.001,
+ comment = "companion to font-oth.lua (helpers)",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local lpegmatch = lpeg.match
+local splitter = lpeg.Ct(lpeg.splitat(" "))
+
+local collect_lookups = fonts.otf.collect_lookups
+
+-- For the moment there is no need to cache this but this might
+-- happen when I get the feeling that there is a performance
+-- penalty involved.
+
+function fonts.otf.get_alternate(tfmdata,k,kind,value)
+ if value then
+ local shared = tfmdata.shared
+ local otfdata = shared and shared.otfdata
+ if otfdata then
+ local validlookups, lookuplist = collect_lookups(otfdata,kind,tfmdata.script,tfmdata.language)
+ if validlookups then
+ local lookups = tfmdata.descriptions[k].slookups -- we assume only slookups (we can always extend)
+ if lookups then
+ local unicodes = tfmdata.unicodes -- names to unicodes
+ local choice = tonumber(value)
+ for l=1,#lookuplist do
+ local lookup = lookuplist[l]
+ local p = lookups[lookup]
+ if p then
+ local pc = p[2] -- p.components
+ if pc then
+ pc = lpegmatch(splitter,pc)
+ return unicodes[pc[choice] or pc[#pc]]
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ return k
+end
diff --git a/tex/context/base/font-pat.lua b/tex/context/base/font-pat.lua
index b6531abb9..9f679f663 100644
--- a/tex/context/base/font-pat.lua
+++ b/tex/context/base/font-pat.lua
@@ -108,19 +108,19 @@ local function patch_domh(data,filename,threshold)
m.DisplayOperatorMinHeight = threshold
end
end
- if tex.luatexversion < 48 then
- for _, g in next, data.glyphs do
- local name = g.name
- if find(name,"^integral$") or find(name,"^integral%.vsize") then
- local width, italic = g.width or 0, g.italic_correction or 0
- local newwidth = width - italic
- if trace_loading then
- report_otf("patching width of %s: %s (width) - %s (italic) = %s",name,width,italic,newwidth)
- end
- g.width = newwidth
- end
- end
- end
+-- if tex.luatexversion < 48 then
+-- for _, g in next, data.glyphs do
+-- local name = g.name
+-- if find(name,"^integral$") or find(name,"^integral%.vsize") then
+-- local width, italic = g.width or 0, g.italic_correction or 0
+-- local newwidth = width - italic
+-- if trace_loading then
+-- report_otf("patching width of %s: %s (width) - %s (italic) = %s",name,width,italic,newwidth)
+-- end
+-- g.width = newwidth
+-- end
+-- end
+-- end
end
patches["cambria"] = function(data,filename) patch_domh(data,filename,2800) end
diff --git a/tex/context/base/grph-epd.lua b/tex/context/base/grph-epd.lua
new file mode 100644
index 000000000..c687e40a8
--- /dev/null
+++ b/tex/context/base/grph-epd.lua
@@ -0,0 +1,23 @@
+if not modules then modules = { } end modules ['grph-epd'] = {
+ version = 1.001,
+ comment = "companion to grph-epd.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local variables = interfaces.variables
+
+-- todo: page, name, file, url
+
+function figures.mergegoodies(optionlist)
+ local options = aux.settings_to_hash(optionlist)
+ local all = options[variables.all] or options[variables.yes]
+ if all or options[variables.reference] then
+ backends.codeinjections.mergereferences()
+ end
+ if all or options[variables.layer] then
+ backends.codeinjections.mergelayers()
+ end
+
+end
diff --git a/tex/context/base/grph-epd.mkiv b/tex/context/base/grph-epd.mkiv
new file mode 100644
index 000000000..b23631b79
--- /dev/null
+++ b/tex/context/base/grph-epd.mkiv
@@ -0,0 +1,58 @@
+%D \module
+%D [ file=grph-epd,
+%D version=2010.07.29,
+%D title=\CONTEXT\ Graphic Macros,
+%D subtitle=Merging 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.
+
+\writestatus{loading}{ConTeXt Graphic Macros / Merging Coodies}
+
+\unprotect
+
+\registerctxluafile{lpdf-epd}{1.001}
+\registerctxluafile{lpdf-epa}{1.001}
+\registerctxluafile{grph-epd}{1.001}
+
+\def\figurereference {\ctxlua{figures.tprint("status","reference")}}
+
+\defineoverlay[epdf-overlay][\directsetup{epdf-overlay}]
+
+\startsetups epdf-overlay
+ \ctxlua{figures.mergegoodies("\@@efinteraction")}%
+ \reference[\figurereference]{}% todo: dest area
+\stopsetups
+
+\def\doaddpdffiguregoodies
+ {\global\setbox\foundexternalfigure\vbox\bgroup
+ \framed[\c!offset=\v!overlay,\c!background={\v!foreground,epdf-overlay}]{\box\foundexternalfigure}%
+ \egroup}
+
+\appendtoks
+ \iflocation\doif\figurefiletype{pdf}{\doifnot\@@efinteraction\v!none\doaddpdffiguregoodies}\fi
+\to \externalfigurepostprocessors
+
+\protect \endinput
+
+% /Properties << /xxxx 22 0 R >>
+% 21 0 obj << /Type /OCG /Name (xxxx) >> endobj
+% 22 0 obj << /OCGs [ 21 0 R ] /Type /OCMD >> endobj
+
+% \def\setepdflayer#1#2#3#4#5#6% x y w h (in bp) 0/1 destination
+% {\setlayer
+% [epdflinks]
+% [\c!x=#1bp,\c!y=#1\s!bp,\c!preset=\v!leftbottom]
+% {\button
+% [\c!width=#3\s!bp,\c!height=#4\s!bp,\c!offset=\v!overlay,\c!frame=\ifnum#5=1 on\else\v!off]%
+% {}[#6]}}
+
+% \def\setepdflayer#1#2#3#4#5#6% x y w h (in bp) 0/1 destination
+% {\setlayer
+% [epdflinks]
+% [\c!x=#1bp,\c!y=#1\s!bp,\c!preset=\v!leftbottom]
+% {\gotowdhtbox{#3\s!bp}{#4\s!bp}[#6]}}
diff --git a/tex/context/base/grph-fig.mkiv b/tex/context/base/grph-fig.mkiv
index e10dc0a32..0cf9bea2b 100644
--- a/tex/context/base/grph-fig.mkiv
+++ b/tex/context/base/grph-fig.mkiv
@@ -41,11 +41,14 @@
\def\dodoplaceexternalfigure[#1][#2][#3][#4][#5]%
{\bgroup
+\dostarttagged\t!image\empty
\pushmacro\textunderscore
\edef\textunderscore{\string_}% brrr, temp hack, still needed?
\calculateexternalfigure[][#1][#2][#3][#4][#5]% [] is dummy dwcomp
\popmacro\textunderscore
+\global\setbox\foundexternalfigure\naturalvbox attr \imageattribute 2 {\box\foundexternalfigure}%
\box\foundexternalfigure
+\dostoptagged
\egroup}
\def\externalfigurereplacement#1#2#3%
@@ -576,6 +579,7 @@
[\c!option=,
\c!object=\v!yes, % we only check for no
\c!reset=\v!no,
+ \c!interaction=\v!none,
\c!maxwidth=\@@efwidth,
\c!maxheight=\@@efheight,
\c!bodyfont=\bodyfontsize,
diff --git a/tex/context/base/grph-inc.lua b/tex/context/base/grph-inc.lua
index c933d6a5f..6fa611694 100644
--- a/tex/context/base/grph-inc.lua
+++ b/tex/context/base/grph-inc.lua
@@ -35,6 +35,8 @@ 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.
]]--
+-- commands.writestatus -> report
+
local format, lower, find, match, gsub, gmatch = string.format, string.lower, string.find, string.match, string.gsub, string.gmatch
local texsprint, texbox = tex.sprint, tex.box
local contains = table.contains
@@ -227,40 +229,45 @@ do
local figuredata = { }
local callstack = { }
- function figures.new()
+ function figures.new() -- we could use metatables status -> used -> request but it needs testing
+ local request = {
+ name = false,
+ label = false,
+ format = false,
+ page = false,
+ width = false,
+ height = false,
+ preview = false,
+ ["repeat"] = false,
+ controls = false,
+ display = false,
+ conversion = false,
+ cache = false,
+ prefix = false,
+ size = false,
+ }
+ local used = {
+ fullname = false,
+ format = false,
+ name = false,
+ path = false,
+ suffix = false,
+ width = false,
+ height = false,
+ }
+ local status = {
+ status = 0,
+ converted = false,
+ cached = false,
+ fullname = false,
+ format = false,
+ }
+ -- setmetatable(status, { __index = used })
+ -- setmetatable(used, { __index = request })
figuredata = {
- request = {
- name = false,
- label = false,
- format = false,
- page = false,
- width = false,
- height = false,
- preview = false,
- ["repeat"] = false,
- controls = false,
- display = false,
- conversion = false,
- cache = false,
- prefix = false,
- size = false,
- },
- used = {
- fullname = false,
- format = false,
- name = false,
- path = false,
- suffix = false,
- width = false,
- height = false,
- },
- status = {
- status = 0,
- converted = false,
- cached = false,
- fullname = false,
- format = false,
- },
+ request = request,
+ used = used,
+ status = status,
}
return figuredata
end
@@ -649,13 +656,13 @@ 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
+ local fullname = l.fullname or foundname
if fullname then
- du.format = l.format or false
+ 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
+ ds.format = l.format
+ ds.status = (l.found and 10) or 0
end
return data
end
@@ -699,6 +706,7 @@ function figures.done(data)
ds.height = box.height
ds.xscale = ds.width /(du.width or 1)
ds.yscale = ds.height/(du.height or 1)
+ ds.page = ds.page or du.page or dr.page -- sort of redundant but can be limited
--~ print(table.serialize(figures.current()))
return data
end
diff --git a/tex/context/base/grph-inc.mkiv b/tex/context/base/grph-inc.mkiv
index 16ee1097a..639ca7d75 100644
--- a/tex/context/base/grph-inc.mkiv
+++ b/tex/context/base/grph-inc.mkiv
@@ -77,6 +77,7 @@
\def\figurexscale {\ctxlua{figures.tprint("status","xscale",1)}}
\def\figureyscale {\ctxlua{figures.tprint("status","yscale",1)}}
+\def\figuresize {\ctxlua{figures.tprint("request","size")}}
\def\figurelabel {\ctxlua{figures.tprint("request","label")}}
\def\figurefileoriginal {\ctxlua{figures.tprint("request","name")}}
\def\figurefilepage {\ctxlua{figures.tprint("request","page",1)}}
@@ -151,6 +152,8 @@
%
\let\@@efforegroundcolor\empty
%
+ \let\@@efinteraction\@@exinteraction
+ %
\let\@@efhfactor \empty
\let\@@efwfactor \empty
\let\@@effactor \empty
diff --git a/tex/context/base/lang-ini.mkiv b/tex/context/base/lang-ini.mkiv
index 24b0ec6f4..37f3fdb10 100644
--- a/tex/context/base/lang-ini.mkiv
+++ b/tex/context/base/lang-ini.mkiv
@@ -220,12 +220,17 @@
\unexpanded\def\setuplanguage
{\dodoubleempty\dosetuplanguage}
+\ifdefined\docomplexlanguage \else \let\docomplexlanguage\relax \fi
+
\def\dosetuplanguage[#1][#2]%
{\ifsecondargument
+ \pushmacro\currentlanguage % can be default
\edef\currentsetuplanguage{\reallanguagetag{#1}}%
\getparameters[\??la\currentsetuplanguage][#2]%
\the\everysetuplanguage
- \doif\currentsetuplanguage\currentlanguage\docomplexlanguage
+ \popmacro\currentlanguage
+ %\doif\currentsetuplanguage\currentlanguage we can have influenced inheritance (default)
+ \docomplexlanguage
\else
\let\currentsetuplanguage\currentlanguage
\getparameters[\??la\currentsetuplanguage][#1]%
@@ -273,6 +278,12 @@
\c!rightcompoundhyphen=\compoundhyphen,
\c!leftcompoundhyphen=]
+% to be tested:
+%
+% \setuplanguage
+% [\s!default]
+% [\c!righthyphenchar="AD]
+
%D The values \type {leftsentence} and \type
%D {rightsentence} can be (and are) used to implement
%D automatic subsentence boundary glyphs, like in {\fr
diff --git a/tex/context/base/lang-lab.mkiv b/tex/context/base/lang-lab.mkiv
index 42f2db8ff..545a64455 100644
--- a/tex/context/base/lang-lab.mkiv
+++ b/tex/context/base/lang-lab.mkiv
@@ -41,14 +41,15 @@
\let\handletextprefix\relax
-\newconditional\protecttextprefixes
+\let\protecttextprefixes\zerocount
\let\currenttextprefixtag \s!unknown
\let\currenttextprefixclass\s!unknown
-\unexpanded\def\setupheadtext {\setfalse\protecttextprefixes\let\currenttextprefixclass\??mh\dodoubleempty\dosetupsometextprefix}
-\unexpanded\def\setuplabeltext {\setfalse\protecttextprefixes\let\currenttextprefixclass\??ml\dodoubleempty\dosetupsometextprefix}
-\unexpanded\def\setupmathlabeltext{\setfalse\protecttextprefixes\let\currenttextprefixclass\??mm\dodoubleempty\dosetupsometextprefix}
+\unexpanded\def\setupheadtext {\let\protecttextprefixes\zerocount\let\currenttextprefixclass\??mh\dodoubleempty\dosetupsometextprefix}
+\unexpanded\def\setuplabeltext {\let\protecttextprefixes\zerocount\let\currenttextprefixclass\??ml\dodoubleempty\dosetupsometextprefix}
+\unexpanded\def\setupmathlabeltext{\let\protecttextprefixes\zerocount\let\currenttextprefixclass\??mm\dodoubleempty\dosetupsometextprefix}
+\unexpanded\def\setuptaglabeltext {\let\protecttextprefixes\plustwo \let\currenttextprefixclass\??me\dodoubleempty\dosetupsometextprefix}
\def\dosetupsometextprefix[#1][#2]%
{\ifsecondargument
@@ -66,14 +67,19 @@
{\doassignsometextprefix{#1}[#2,,]}
\def\doassignsometextprefix#1%
- {\ifconditional\protecttextprefixes
+ {\ifcase\protecttextprefixes
+ % no checking
+ \expandafter\doassignsometextprefixyes
+ \or
+ % checking
\ifcsname\currenttextprefixclass\currenttextprefixtag#1\endcsname
\expandafter\expandafter\expandafter\doassignsometextprefixnop
\else
\expandafter\expandafter\expandafter\doassignsometextprefixyes
\fi
- \else
- \expandafter\doassignsometextprefixyes
+ \or
+ % simple assignment (a bit overkill but it fits in the whole)
+ \expandafter\doassignsometextprefixdumb
\fi{#1}}
\ifdefined\Word\else \let\Word\relax \fi
@@ -92,12 +98,15 @@
\expandafter\def\csname\currenttextprefixclass\currenttextprefixtag#1\endcsname{{#2}\empty}%
\fi
\else
- \expandafter\def\csname\currenttextprefixclass\currenttextprefixtag#1\endcsname{{#2}{#3}}%
+ \expandafter\def\csname\currenttextprefixclass\currenttextprefixtag#1\endcsname{{#2}{#3}}%
\fi}
\def\doassignsometextprefixnop#1[#2]%
{}
+\def\doassignsometextprefixdumb#1[#2,#3]%
+ {\expandafter\def\csname\currenttextprefixclass\currenttextprefixtag#1\endcsname{#2}}
+
%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.
@@ -128,6 +137,7 @@
\def\labellanguage {\reallanguagetag{\defaultlanguage\currentmainlanguage}}
\def\headlanguage {\reallanguagetag{\defaultlanguage\currentmainlanguage}}
\def\mathlabellanguage{\reallanguagetag{\defaultlanguage\currentmainlanguage}}
+\def\taglabellanguage {\reallanguagetag{\defaultlanguage\currentmainlanguage}}
\appendtoks \let\labellanguage\currentlanguage \to \everycurrentdate
@@ -135,7 +145,8 @@
\def\dogetupsomelabeltext {\dodogetupsomelabeltext \labellanguage } % second argument is textlabel
\def\dogetupsomeheadtext {\dodogetupsomeheadtext \headlanguage } % second argument is headlabel
-\def\dogetupsomemathlabeltext{\dodogetupsomemathlabeltext\mathlabellanguage } % second argument is headlabel
+\def\dogetupsomemathlabeltext{\dodogetupsomemathlabeltext\mathlabellanguage }
+\def\dogetupsometaglabeltext {\dodogetupsometaglabeltext \taglabellanguage }
\def\dodogetupsomelabeltext#1#2%
{\ifcsname\??ml#1#2\endcsname
@@ -176,6 +187,19 @@
\let\thetextprefix\dummytextprefix
\fi\fi\fi\fi}
+\def\dodogetupsometaglabeltext#1#2% special
+ {\ifcsname\??me#1#2\endcsname
+ \csname\??me#1#2\endcsname
+ \else\ifcsname\??la\mathlabellanguage\s!default\endcsname
+ \expandafter\dodogetupsomemathlabeltext\csname\??la\mathlabellanguage\s!default\endcsname{#2}%
+ \else\ifcsname\??me#2\endcsname
+ \csname\??me#2\endcsname
+ \else\ifcsname\??me\s!en#2\endcsname
+ \csname\??me\s!en#2\endcsname
+ \else
+ #2%
+ \fi\fi\fi\fi}
+
% The WORD variants are a bit inefficient when #1/#2 are empty but they are
% seldom used (one can better set the style).
@@ -224,9 +248,9 @@
%D head and label texts without replacing predefined ones.
%D These are internal macros.
-\def\presetheadtext {\settrue\protecttextprefixes\let\currenttextprefixclass\??mh\dodoubleempty\dosetupsometextprefix}
-\def\presetlabeltext {\settrue\protecttextprefixes\let\currenttextprefixclass\??ml\dodoubleempty\dosetupsometextprefix}
-\def\presetmathlabeltext{\settrue\protecttextprefixes\let\currenttextprefixclass\??mm\dodoubleempty\dosetupsometextprefix}
+\def\presetheadtext {\let\protecttextprefixes\plusone\let\currenttextprefixclass\??mh\dodoubleempty\dosetupsometextprefix}
+\def\presetlabeltext {\let\protecttextprefixes\plusone\let\currenttextprefixclass\??ml\dodoubleempty\dosetupsometextprefix}
+\def\presetmathlabeltext{\let\protecttextprefixes\plusone\let\currenttextprefixclass\??mm\dodoubleempty\dosetupsometextprefix}
%D \macros
%D {translate}
diff --git a/tex/context/base/lang-mis.mkiv b/tex/context/base/lang-mis.mkiv
index 0df45877b..11374e8b5 100644
--- a/tex/context/base/lang-mis.mkiv
+++ b/tex/context/base/lang-mis.mkiv
@@ -277,7 +277,7 @@
\let\domathmodediscretionary\handlemathmodediscretionary
-\def\dotextmodediscretionary#1%
+\def\dotextmodediscretionary#1% grouped !
{\bgroup
\let\nextnextnext\egroup
\def\next##1#1%
diff --git a/tex/context/base/lang-sla.tex b/tex/context/base/lang-sla.tex
index 45a92b289..7892123bb 100644
--- a/tex/context/base/lang-sla.tex
+++ b/tex/context/base/lang-sla.tex
@@ -121,7 +121,7 @@
\c!rightquote=\upperrightsingleninequote,
\c!leftquotation=\lowerleftdoubleninequote,
\c!rightquotation=\upperrightdoubleninequote,
- \c!date={\v!day,\ ,\v!month,\ ,\v!year},
+ \c!date={\v!day,{.},\ ,\v!month,\ ,\v!year},
\s!mapping=ec,
\s!encoding=ec]
diff --git a/tex/context/base/lpdf-ano.lua b/tex/context/base/lpdf-ano.lua
index f6392fd37..89ccb2235 100644
--- a/tex/context/base/lpdf-ano.lua
+++ b/tex/context/base/lpdf-ano.lua
@@ -35,17 +35,17 @@ local specials = jobreferences.specials
local handlers = jobreferences.handlers
local executers = jobreferences.executers
-local pdfdictionary = lpdf.dictionary
-local pdfarray = lpdf.array
-local pdfreference = lpdf.reference
-local pdfunicode = lpdf.unicode
-local pdfconstant = lpdf.constant
-local pdfflushobject = lpdf.flushobject
-local pdfreserveobject = lpdf.reserveobject
-local pdfannotation = nodes.pdfannotation
-local pdfdestination = nodes.pdfdestination
-
-local pdfpagereference = tex.pdfpageref
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfreference = lpdf.reference
+local pdfunicode = lpdf.unicode
+local pdfconstant = lpdf.constant
+local pdfflushobject = lpdf.flushobject
+local pdfreserveobject = lpdf.reserveobject
+local pdfpagereference = lpdf.pagereference
+
+local pdfannotation_node = nodes.pdfannotation
+local pdfdestination_node = nodes.pdfdestination
local pdf_uri = pdfconstant("URI")
local pdf_gotor = pdfconstant("GoToR")
@@ -60,16 +60,18 @@ local pdf_border = pdfarray { 0, 0, 0 }
local cache = { }
local function pagedest(n)
- local pd = cache[n]
- if not pd then
- local a = pdfarray {
- pdfreference(pdfpagereference(n)),
- pdfconstant("Fit")
- }
- pd = pdfreference(pdfflushobject(a))
- cache[n] = pd
+ if n > 0 then
+ local pd = cache[n]
+ if not pd then
+ local a = pdfarray {
+ pdfreference(pdfpagereference(n)),
+ pdfconstant("Fit")
+ }
+ pd = pdfreference(pdfflushobject(a))
+ cache[n] = pd
+ end
+ return pd
end
- return pd
end
lpdf.pagedest = pagedest
@@ -97,10 +99,17 @@ local function link(url,filename,destination,page,actions)
URI = url,
}
elseif filename and filename ~= "" then
+ -- no page ?
+ if destination == "" then
+ destination = nil
+ end
+ if not destination and page then
+ destination = pdfarray { page - 1, pdfconstant("Fit") }
+ end
return pdfdictionary {
S = pdf_gotor, -- can also be pdf_launch
F = filename,
- D = (destination and destination ~= "" and destination), -- or defaultdestination,
+ D = destination or defaultdestination, -- D is mandate
NewWindow = (actions.newwindow and true) or nil,
}
elseif destination and destination ~= "" then
@@ -195,7 +204,7 @@ local function pdfaction(actions)
end
end
-lpdf.pdfaction = pdfaction
+lpdf.action = pdfaction
function codeinjections.prerollreference(actions)
local main = actions and pdfaction(actions)
@@ -205,6 +214,7 @@ function codeinjections.prerollreference(actions)
Border = pdf_border,
H = (not actions.highlight and pdf_n) or nil,
A = main,
+ F = 4, -- print (mandate in pdf/a)
-- does not work at all in spite of specification
-- OC = (actions.layer and lpdf.layerreferences[actions.layer]) or nil,
-- OC = backends.pdf.layerreference(actions.layer),
@@ -238,7 +248,7 @@ function nodeinjections.reference(width,height,depth,prerolled)
if trace_references then
report_references("w=%s, h=%s, d=%s, a=%s",width,height,depth,prerolled)
end
- return pdfannotation(width,height,depth,prerolled)
+ return pdfannotation_node(width,height,depth,prerolled)
end
end
@@ -246,7 +256,7 @@ function nodeinjections.destination(width,height,depth,name,view)
if trace_destinations then
report_destinations("w=%s, h=%s, d=%s, n=%s, v=%s",width,height,depth,name,view or "no view")
end
- return pdfdestination(width,height,depth,name,view)
+ return pdfdestination_node(width,height,depth,name,view)
end
-- runners and specials
@@ -337,7 +347,7 @@ function specials.page(var,actions) -- better resolve in strc-ref
local file = var.f
if file then
file = jobreferences.checkedfile(file)
- return link(nil,file,nil,p or var.operation,actions)
+ return link(nil,file,nil,var.operation,actions)
else
local p = jobreferences.pages[var.operation]
if type(p) == "function" then
diff --git a/tex/context/base/lpdf-epa.lua b/tex/context/base/lpdf-epa.lua
new file mode 100644
index 000000000..35c0c086b
--- /dev/null
+++ b/tex/context/base/lpdf-epa.lua
@@ -0,0 +1,162 @@
+if not modules then modules = { } end modules ['lpdf-epa'] = {
+ version = 1.001,
+ comment = "companion to lpdf-epa.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This is a rather experimental feature and the code will probably
+-- change.
+
+local type, tonumber = type, tonumber
+local format = string.format
+
+local trace_links = false trackers.register("figures.links", function(v) trace_links = v end)
+
+local report_link = logs.new("links")
+
+local variables = interfaces.variables
+
+local function add_link(x,y,w,h,destination,what)
+ if trace_links then
+ report_link("dx: %04i, dy: %04i, wd: %04i, ht: %04i, destination: %s, type: %s",x,y,w,h,destination,what)
+ end
+ context.setlayer (
+ { "epdflinks" },
+ { x = x .. "bp", y = y .. "bp", preset = "leftbottom" },
+ function()
+ -- context.blackrule { width = w.."bp", height = h.."bp", depth = "0bp" }
+ context.button (
+ {
+ width = w.."bp",
+ height = h.."bp",
+ offset = variables.overlay,
+ frame = trace_links and variables.on or variables.off,
+ },
+ "",
+ { destination }
+ )
+ end
+ )
+end
+
+local function link_goto(x,y,w,h,document,annotation,pagesdata,pagedata,namespace)
+ -- print("border",table.unpack(annotation.Border.all))
+ -- print("flags",annotation.F)
+ -- print("pagenumbers",pagedata.reference.num,destination[1].num)
+ -- print("pagerefs",pagedata.number,pagesdata.references[destination[1].num])
+ local destination = annotation.A.D -- [ 18 0 R /Fit ]
+ local what = "page"
+ if type(destination) == "string" then
+ local destinations = document.Catalog.Destinations
+ local wanted = destinations[destination]
+ destination = wanted and wanted.D
+ if destination then what = "named" end
+ end
+ local whereto = destination and destination[1] -- array
+ if whereto and whereto.num then
+ local currentpage = pagedata.number
+ local destinationpage = pagesdata.references[whereto.num]
+ add_link(x,y,w,h,namespace .. destinationpage,what)
+ return
+ end
+end
+
+local function link_uri(x,y,w,h,document,annotation)
+ local url = annotation.A.URI
+ if url then
+ add_link(x,y,w,h,format("url(%s)",url),"url")
+ end
+end
+
+local function link_file(x,y,w,h,document,annotation)
+ local filename = annotation.A.F
+ if filename then
+ local destination = annotation.A.D
+ if not destination then
+ add_link(x,y,w,h,format("file(%s)",filename),"file")
+ elseif type(destination) == "string" then
+ add_link(x,y,w,h,format("%s::%s",filename,destination),"file (named)")
+ else
+ destination = destination[1] -- array
+ if tonumber(destination) then
+ add_link(x,y,w,h,format("%s::page(%s)",filename,destination),"file (page)")
+ else
+ add_link(x,y,w,h,format("file(%s)",filename),"file")
+ end
+ end
+ end
+end
+
+function backends.codeinjections.mergereferences(specification)
+ if figures and not specification then
+ specification = figures and figures.current()
+ specification = specification and specification.status
+ end
+ if specification then
+ local fullname = specification.fullname
+ local document = lpdf.load(fullname)
+ if document then
+ local pagenumber = specification.page or 1
+ local xscale = specification.yscale or 1
+ local yscale = specification.yscale or 1
+ local size = specification.size or "crop" -- todo
+ local pagesdata = document.Catalog.Pages
+ local pagedata = pagesdata[pagenumber]
+ local annotations = pagedata.Annots
+ local namespace = format("lpdf-epa-%s-",file.removesuffix(file.basename(fullname)))
+ local reference = namespace .. pagenumber
+ if annotations.size > 0 then
+ local llx, lly, urx, ury = table.unpack(pagedata.MediaBox.all)
+ local width, height = xscale * (urx - llx), yscale * (ury - lly) -- \\overlaywidth, \\overlayheight
+ context.definelayer( { "epdflinks" }, { height = height.."bp" , width = width.."bp" })
+ for i=1,annotations.size do
+ local annotation = annotations[i]
+ local subtype = annotation.Subtype
+ local a_llx, a_lly, a_urx, a_ury = table.unpack(annotation.Rect.all)
+ local x, y = xscale * (a_llx - llx), yscale * (a_lly - lly)
+ local w, h = xscale * (a_urx - a_llx), yscale * (a_ury - a_lly)
+ if subtype == "Link" then
+ local linktype = annotation.A.S
+ if linktype == "GoTo" then
+ link_goto(x,y,w,h,document,annotation,pagesdata,pagedata,namespace)
+ elseif linktype == "GoToR" then
+ link_file(x,y,w,h,document,annotation)
+ elseif linktype == "URI" then
+ link_uri(x,y,w,h,document,annotation)
+ elseif trace_links then
+ report_link("unsupported link annotation '%s'",linktype)
+ end
+ elseif trace_links then
+ report_link("unsupported annotation '%s'",subtype)
+ end
+ end
+ context.flushlayer { "epdflinks" }
+ context("\\gdef\\figurereference{%s}",reference) -- global
+ specification.reference = reference
+ return namespace
+ end
+ end
+ end
+ return ""-- no namespace, empty, not nil
+end
+
+function backends.codeinjections.mergelayers(specification)
+ if not specification then
+ specification = figures and figures.current()
+ specification = specification and specification.status
+ end
+ if specification then
+ local fullname = specification.fullname
+ local document = lpdf.load(fullname)
+ if document then
+ local pagenumber = specification.page or 1
+ local pagesdata = document.Catalog.Pages
+ local pagedata = pagesdata[pagenumber]
+ local resources = pagedata.Resources
+--~ table.print(resources)
+--~ local properties = resources.Properties
+ end
+ end
+end
diff --git a/tex/context/base/lpdf-epd.lua b/tex/context/base/lpdf-epd.lua
new file mode 100644
index 000000000..23ab0674c
--- /dev/null
+++ b/tex/context/base/lpdf-epd.lua
@@ -0,0 +1,246 @@
+if not modules then modules = { } end modules ['lpdf-epd'] = {
+ version = 1.001,
+ comment = "companion to lpdf-epa.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This is an experimental layer around the epdf library. Because that
+-- library is not yet finished and will get a clear api (independent of
+-- the underlying pdf library which has an instable api) it will take
+-- a while before this module is completed. Also, some integration with
+-- other lpdf code might happen (i.e. we might generate lpdf objects).
+
+local setmetatable, rawset = setmetatable, rawset
+
+-- used:
+--
+-- arrayGet arrayGetNF dictLookup getTypeName arrayGetLength
+-- getNum getString getBool getName getRef
+-- getResourceDict getMediaBox getCropBox getBleedBox getTrimBox getArtBox
+-- getPageRef getKindName findDestgetNumPages getDests getPage getCatalog getAnnots
+
+-- -- -- helpers -- -- --
+
+local cache_lookups = false
+
+local checked_access
+
+local array_access = {
+ __index = function(t,k)
+ local d = t.__data__
+ if tonumber(k) then
+ return checked_access(t,k,d:arrayGetNF(k))
+ elseif k == "all" then
+ local result = { }
+ for i=1,t.size do
+ result[i] = checked_access(t,k,d:arrayGetNF(i))
+ end
+ return result
+ elseif k == "width" then
+ return checked_access(t,k,d:arrayGetNF(3)) - checked_access(t,k,d:arrayGetNF(1))
+ elseif k == "height" then
+ return checked_access(t,k,d:arrayGetNF(4)) - checked_access(t,k,d:arrayGetNF(2))
+ end
+ end,
+}
+
+local dictionary_access = {
+ __index = function(t,k)
+ return checked_access(t,k,t.__data__:dictLookup(k))
+ end
+}
+
+checked_access = function(tab,key,v)
+ local n = v:getTypeName()
+--~ print("!!!!!!!!!!!!!!",n)
+ if n == "array" then
+ local t = { __data__ = v, size = v:arrayGetLength() }
+ setmetatable(t,array_access)
+ if cache_lookups then rawset(tab,key,t) end
+ return t
+ elseif n == "dictionary" then
+ local t = { __data__ = v, }
+ setmetatable(t,dictionary_access)
+ if cache_lookups then rawset(tab,key,t) end
+ return t
+ elseif n == "real" or n == "integer" then
+ return v:getNum()
+ elseif n == "string" then
+ return v:getString()
+ elseif n == "boolean" then
+ return v:getBool()
+ elseif n == "name" then
+ return v:getName()
+ elseif n == "ref" then
+ return v:getRef(v.num,v.gen)
+ else
+ return v
+ end
+end
+
+local basic_annots_access = {
+ __index = function(t,k)
+ local a = {
+ __data__ = t.__data__:arrayGet(k),
+ }
+ setmetatable(a,dictionary_access)
+ if cache_lookups then rawset(t,k,a) end
+ return a
+ end
+}
+
+local basic_resources_access = { -- == dictionary_access
+ __index = function(t,k)
+--~ local d = t.__data__
+--~ print(d)
+--~ print(d:getTypeName())
+ return checked_access(t,k,t.__data__:dictLookup(k))
+ end
+}
+
+local basic_box_access = {
+ __index = function(t,k)
+ local d = t.__data__
+ if k == "all" then return { d.x1, d.y1, d.x2, d.y2 }
+ elseif k == "width" then return d.x2 - d.x1
+ elseif k == "height" then return d.y2 - d.y1
+ elseif k == 1 then return d.x1
+ elseif k == 2 then return d.y1
+ elseif k == 3 then return d.x2
+ elseif k == 4 then return d.y2
+ else return 0 end
+ end
+}
+
+-- -- -- pages -- -- --
+
+local page_access = {
+ __index = function(t,k)
+ local d = t.__data__
+ if k == "Annots" then
+ local annots = d:getAnnots()
+ local a = {
+ __data__ = annots,
+ size = annots:arrayGetLength()
+ }
+ setmetatable(a,basic_annots_access)
+ rawset(t,k,a)
+ return a
+ elseif k == "Resources" then
+ local r = {
+ __data__ = d:getResourceDict(),
+ }
+ setmetatable(r,basic_resources_access)
+ rawset(t,k,r)
+ return r
+ elseif k == "MediaBox" or k == "TrimBox" or k == "CropBox" or k == "ArtBox" or k == "BleedBox" then
+ local b = {
+ -- __data__ = d:getMediaBox(),
+ __data__ = d["get"..k](d),
+ }
+ setmetatable(b,basic_box_access)
+ rawset(t,k,b)
+ return b
+ end
+ end
+}
+
+-- -- -- catalog -- -- --
+
+local destination_access = {
+ __index = function(t,k)
+ if k == "D" then
+ local d = t.__data__
+ local p = {
+ d:getPageRef(k), d:getKindName(k)
+ }
+ if cache_lookups then rawset(t,k,p) end -- not needed
+ return p
+ end
+ end
+}
+
+local destinations_access = {
+ __index = function(t,k)
+ local d = t.__catalog__
+ local p = {
+ __data__ = d:findDest(k),
+ }
+ setmetatable(p,destination_access)
+ if cache_lookups then rawset(t,k,p) end
+ return p
+ end
+}
+
+local catalog_access = {
+ __index = function(t,k)
+ local c = t.__catalog__
+ if k == "Pages" then
+ local s = c:getNumPages()
+ local r = {
+ }
+ local p = {
+ __catalog__ = c,
+ size = s,
+ references = r,
+ }
+ -- we load all pages as we need to resolve refs
+ for i=1,s do
+ local di, ri = c:getPage(i), c:getPageRef(i)
+ local pi = {
+ __data__ = di,
+ reference = ri,
+ number = i,
+ }
+ setmetatable(pi,page_access)
+ p[i], r[ri.num] = pi, i
+ end
+ -- setmetatable(p,pages_access)
+ rawset(t,k,p)
+ return p
+ elseif k == "Destinations" or k == "Dest" then
+ local d = c:getDests()
+ local p = {
+ __catalog__ = c,
+ }
+ setmetatable(p,destinations_access)
+ rawset(t,k,p)
+ return p
+ elseif k == "Metadata" then
+ local m = c:readMetadata()
+ local p = { -- we fake a stream dictionary
+ __catalog__ = c,
+ stream = m,
+ Type = "Metadata",
+ Subtype = "XML",
+ Length = #m,
+ }
+ -- rawset(t,k,p)
+ return p
+ end
+ end
+}
+
+local document_access = {
+ __index = function(t,k)
+ if k == "Catalog" then
+ local c = {
+ __catalog__ = t.__root__:getCatalog(),
+ }
+ setmetatable(c,catalog_access)
+ rawset(t,k,c)
+ return c
+ end
+ end
+}
+
+function lpdf.load(filename)
+ local document = {
+ __root__ = epdf.open(filename),
+ filename = filename,
+ }
+ setmetatable(document,document_access)
+ return document
+end
diff --git a/tex/context/base/lpdf-fld.lua b/tex/context/base/lpdf-fld.lua
index 893962b0e..455ddcf5f 100644
--- a/tex/context/base/lpdf-fld.lua
+++ b/tex/context/base/lpdf-fld.lua
@@ -27,17 +27,18 @@ local registrations = backends.pdf.registrations
local registeredsymbol = codeinjections.registeredsymbol
-local pdfstream = lpdf.stream
-local pdfdictionary = lpdf.dictionary
-local pdfarray = lpdf.array
-local pdfreference = lpdf.reference
-local pdfunicode = lpdf.unicode
-local pdfstring = lpdf.string
-local pdfconstant = lpdf.constant
-local pdftoeight = lpdf.toeight
-local pdfflushobject = lpdf.flushobject
-local pdfreserveobject = lpdf.reserveobject
-local pdfannotation = nodes.pdfannotation
+local pdfstream = lpdf.stream
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfreference = lpdf.reference
+local pdfunicode = lpdf.unicode
+local pdfstring = lpdf.string
+local pdfconstant = lpdf.constant
+local pdftoeight = lpdf.toeight
+local pdfflushobject = lpdf.flushobject
+local pdfreserveobject = lpdf.reserveobject
+
+local pdfannotation_node = nodes.pdfannotation
local submitoutputformat = 0 -- 0=unknown 1=HTML 2=FDF 3=XML => not yet used, needs to be checked
@@ -119,7 +120,7 @@ end
local function checked(what)
if what and what ~= "" then
local set, bug = jobreferences.identify("",what)
- return not bug and #set > 0 and lpdf.pdfaction(set)
+ return not bug and #set > 0 and lpdf.action(set)
end
end
@@ -586,7 +587,7 @@ local function finishfields()
end
end
-lpdf.registerdocumentfinalizer(finishfields)
+lpdf.registerdocumentfinalizer(finishfields,"form fields")
local pdf_widget = pdfconstant("Widget")
local pdf_tx = pdfconstant("Tx")
@@ -634,7 +635,7 @@ end
local function save_kid(field,specification,d)
local kn = pdfreserveobject()
field.kids[#field.kids+1] = pdfreference(kn)
- node.write(pdfannotation(specification.width,specification.height,0,d(),kn))
+ node.write(pdfannotation_node(specification.width,specification.height,0,d(),kn))
end
function methods.line(name,specification,variant,extras)
diff --git a/tex/context/base/lpdf-ini.lua b/tex/context/base/lpdf-ini.lua
index e0cc98c27..09fb1d096 100644
--- a/tex/context/base/lpdf-ini.lua
+++ b/tex/context/base/lpdf-ini.lua
@@ -13,8 +13,8 @@ local texwrite, texset, texsprint, ctxcatcodes = tex.write, tex.set, tex.sprint,
local sind, cosd = math.sind, math.cosd
local lpegmatch = lpeg.match
-local pdfreserveobj = pdf and pdf.reserveobj or function() return 1 end -- for testing
-local pdfimmediateobj = pdf and pdf.immediateobj or function() return 2 end -- for testing
+local pdfreserveobject = pdf and pdf.reserveobj or function() return 1 end -- for testing
+local pdfimmediateobject = pdf and pdf.immediateobj or function() return 2 end -- for testing
local trace_finalizers = false trackers.register("backend.finalizers", function(v) trace_finalizers = v end)
local trace_resources = false trackers.register("backend.resources", function(v) trace_resources = v end)
@@ -331,7 +331,7 @@ lpdf.verbose = pdfverbose
local names, cache = { }, { }
function lpdf.reserveobject(name)
- local r = pdfreserveobj()
+ local r = pdfreserveobject()
if name then
names[name] = r
if trace_objects then
@@ -343,7 +343,30 @@ function lpdf.reserveobject(name)
return r
end
---~ local pdfreserveobject = lpdf.reserveobject
+function lpdf.reserveannotation()
+ return pdfreserveobject("annot")
+end
+
+lpdf.immediateobject = pdf.immediateobj
+lpdf.object = pdf.obj -- the table interface, todo: auto attr() and so
+lpdf.pagereference = pdf.pageref or tex.pdfpageref
+
+--~ local pdfobj = pdf.obj
+
+--~ function lpdf.object(t)
+--~ local attr = t.attr
+--~ if type(attr) == "function" then
+--~ t.attr = attr()
+--~ end
+--~ local str = t.string
+--~ if str then
+--~ t.string = tostring(str)
+--~ end
+--~ if not t.type then
+--~ t.type = "raw"
+--~ end
+--~ pdfobj(t)
+--~ end
function lpdf.flushobject(name,data)
if data then
@@ -356,7 +379,7 @@ function lpdf.flushobject(name,data)
report_backends("flushing object data to reserved object with name '%s'",name)
end
end
- return pdfimmediateobj(name,tostring(data))
+ return pdfimmediateobject(name,tostring(data))
else
if trace_objects then
if trace_detail then
@@ -365,20 +388,20 @@ function lpdf.flushobject(name,data)
report_backends("flushing object data to reserved object with number %s",name)
end
end
- return pdfimmediateobj(tostring(data))
+ return pdfimmediateobject(tostring(data))
end
else
if trace_objects and trace_detail then
report_backends("flushing object data -> %s",tostring(name))
end
- return pdfimmediateobj(tostring(name))
+ return pdfimmediateobject(tostring(name))
end
end
function lpdf.sharedobj(content)
local r = cache[content]
if not r then
- r = pdfreference(pdfimmediateobj(content))
+ r = pdfreference(pdfimmediateobject(content))
cache[content] = r
end
return r
@@ -447,6 +470,8 @@ local function resetpageproperties()
pagesattributes = pdfdictionary()
end
+resetpageproperties()
+
local function setpageproperties()
--~ texset("global", "pdfpageresources", pageresources ())
--~ texset("global", "pdfpageattr", pageattributes ())
@@ -460,10 +485,14 @@ function lpdf.addtopageresources (k,v) pageresources [k] = v end
function lpdf.addtopageattributes (k,v) pageattributes [k] = v end
function lpdf.addtopagesattributes(k,v) pagesattributes[k] = v end
-local function set(where,f,when,what)
- when = when or 2
+local function set(where,what,f,when,comment)
+ if type(when) == "string" then
+ when, comment = 2, when
+ elseif not when then
+ when = 2
+ end
local w = where[when]
- w[#w+1] = f
+ w[#w+1] = { f, comment }
if trace_finalizers then
report_backends("%s set: [%s,%s]",what,when,#w)
end
@@ -473,27 +502,29 @@ local function run(where,what)
for i=1,#where do
local w = where[i]
for j=1,#w do
+ local wj = w[j]
if trace_finalizers then
- report_backends("%s finalizer: [%s,%s]",what,i,j)
+ report_backends("%s finalizer: [%s,%s] %s",what,i,j,wj[2] or "")
end
- w[j]()
+ wj[1]()
end
end
end
-function lpdf.registerpagefinalizer(f,when)
- set(pagefinalizers,f,when,"page")
+function lpdf.registerpagefinalizer(f,when,comment)
+ set(pagefinalizers,"page",f,when,comment)
end
-function lpdf.registerdocumentfinalizer(f,when)
- set(documentfinalizers,f,when,"document")
+function lpdf.registerdocumentfinalizer(f,when,comment)
+ set(documentfinalizers,"document",f,when,comment)
end
function lpdf.finalizepage()
if not environment.initex then
- resetpageproperties()
+ -- resetpageproperties() -- maybe better before
run(pagefinalizers,"page")
setpageproperties()
+ resetpageproperties() -- maybe better before
end
end
@@ -507,11 +538,8 @@ function lpdf.finalizedocument()
end
end
-if callbacks.known("finish_pdffile") then
- callbacks.register("finish_pdffile",function() if not environment.initex then run(documentfinalizers,"document") end end)
- function lpdf.finalizedocument() end
-end
-
+--~ callbacks.register("finish_pdfoage", lpdf.finalizepage)
+callbacks.register("finish_pdffile", lpdf.finalizedocument)
-- some minimal tracing, handy for checking the order
@@ -538,22 +566,22 @@ function lpdf.addtocatalog(k,v) if not (lpdf.protectresources and catalog[k]) th
function lpdf.addtoinfo (k,v) if not (lpdf.protectresources and info [k]) then trace_set("info", k) info [k] = v end end
function lpdf.addtonames (k,v) if not (lpdf.protectresources and names [k]) then trace_set("names", k) names [k] = v end end
-local dummy = pdfreserveobj() -- else bug in hvmd due so some internal luatex conflict
+local dummy = pdfreserveobject() -- else bug in hvmd due so some internal luatex conflict
-local r_extgstates, d_extgstates = pdfreserveobj(), pdfdictionary() local p_extgstates = pdfreference(r_extgstates)
-local r_colorspaces, d_colorspaces = pdfreserveobj(), pdfdictionary() local p_colorspaces = pdfreference(r_colorspaces)
-local r_patterns, d_patterns = pdfreserveobj(), pdfdictionary() local p_patterns = pdfreference(r_patterns)
-local r_shades, d_shades = pdfreserveobj(), pdfdictionary() local p_shades = pdfreference(r_shades)
+local r_extgstates, d_extgstates = pdfreserveobject(), pdfdictionary() local p_extgstates = pdfreference(r_extgstates)
+local r_colorspaces, d_colorspaces = pdfreserveobject(), pdfdictionary() local p_colorspaces = pdfreference(r_colorspaces)
+local r_patterns, d_patterns = pdfreserveobject(), pdfdictionary() local p_patterns = pdfreference(r_patterns)
+local r_shades, d_shades = pdfreserveobject(), pdfdictionary() local p_shades = pdfreference(r_shades)
local function checkextgstates () if next(d_extgstates ) then lpdf.addtopageresources("ExtGState", p_extgstates ) end end
local function checkcolorspaces() if next(d_colorspaces) then lpdf.addtopageresources("ColorSpace",p_colorspaces) end end
local function checkpatterns () if next(d_patterns ) then lpdf.addtopageresources("Pattern", p_patterns ) end end
local function checkshades () if next(d_shades ) then lpdf.addtopageresources("Shading", p_shades ) end end
-local function flushextgstates () if next(d_extgstates ) then trace_flush("extgstates") pdfimmediateobj(r_extgstates, tostring(d_extgstates )) end end
-local function flushcolorspaces() if next(d_colorspaces) then trace_flush("colorspaces") pdfimmediateobj(r_colorspaces,tostring(d_colorspaces)) end end
-local function flushpatterns () if next(d_patterns ) then trace_flush("patterns") pdfimmediateobj(r_patterns, tostring(d_patterns )) end end
-local function flushshades () if next(d_shades ) then trace_flush("shades") pdfimmediateobj(r_shades, tostring(d_shades )) end end
+local function flushextgstates () if next(d_extgstates ) then trace_flush("extgstates") pdfimmediateobject(r_extgstates, tostring(d_extgstates )) end end
+local function flushcolorspaces() if next(d_colorspaces) then trace_flush("colorspaces") pdfimmediateobject(r_colorspaces,tostring(d_colorspaces)) end end
+local function flushpatterns () if next(d_patterns ) then trace_flush("patterns") pdfimmediateobject(r_patterns, tostring(d_patterns )) end end
+local function flushshades () if next(d_shades ) then trace_flush("shades") pdfimmediateobject(r_shades, tostring(d_shades )) end end
local collected = pdfdictionary {
ExtGState = p_extgstates,
@@ -571,19 +599,19 @@ function lpdf.adddocumentcolorspace(k,v) d_colorspaces[k] = v end
function lpdf.adddocumentpattern (k,v) d_patterns [k] = v end
function lpdf.adddocumentshade (k,v) d_shades [k] = v end
-lpdf.registerdocumentfinalizer(flushextgstates,3)
-lpdf.registerdocumentfinalizer(flushcolorspaces,3)
-lpdf.registerdocumentfinalizer(flushpatterns,3)
-lpdf.registerdocumentfinalizer(flushshades,3)
+lpdf.registerdocumentfinalizer(flushextgstates,3,"extended graphic states")
+lpdf.registerdocumentfinalizer(flushcolorspaces,3,"color spaces")
+lpdf.registerdocumentfinalizer(flushpatterns,3,"patterns")
+lpdf.registerdocumentfinalizer(flushshades,3,"shades")
-lpdf.registerdocumentfinalizer(flushcatalog,3)
-lpdf.registerdocumentfinalizer(flushinfo,3)
-lpdf.registerdocumentfinalizer(flushnames,3)
+lpdf.registerdocumentfinalizer(flushcatalog,3,"catalog")
+lpdf.registerdocumentfinalizer(flushinfo,3,"info")
+lpdf.registerdocumentfinalizer(flushnames,3,"names")
-lpdf.registerpagefinalizer(checkextgstates,3)
-lpdf.registerpagefinalizer(checkcolorspaces,3)
-lpdf.registerpagefinalizer(checkpatterns,3)
-lpdf.registerpagefinalizer(checkshades,3)
+lpdf.registerpagefinalizer(checkextgstates,3,"extended graphic states")
+lpdf.registerpagefinalizer(checkcolorspaces,3,"color spaces")
+lpdf.registerpagefinalizer(checkpatterns,3,"patterns")
+lpdf.registerpagefinalizer(checkshades,3,"shades")
-- in strc-bkm: lpdf.registerdocumentfinalizer(function() structure.bookmarks.place() end,1)
diff --git a/tex/context/base/lpdf-ini.mkiv b/tex/context/base/lpdf-ini.mkiv
index 7c7dce3ef..64ce6eb43 100644
--- a/tex/context/base/lpdf-ini.mkiv
+++ b/tex/context/base/lpdf-ini.mkiv
@@ -25,6 +25,7 @@
\registerctxluafile{lpdf-fld}{1.001}
\registerctxluafile{lpdf-u3d}{1.001}
\registerctxluafile{lpdf-swf}{1.001}
+\registerctxluafile{lpdf-tag}{1.001}
\unprotect
diff --git a/tex/context/base/lpdf-mis.lua b/tex/context/base/lpdf-mis.lua
index ac471e4e0..0d9061daa 100644
--- a/tex/context/base/lpdf-mis.lua
+++ b/tex/context/base/lpdf-mis.lua
@@ -28,17 +28,16 @@ local copy_node = node.copy
local pdfliteral, register = nodes.pdfliteral, nodes.register
-local pdfdictionary = lpdf.dictionary
-local pdfarray = lpdf.array
-local pdfboolean = lpdf.boolean
-local pdfconstant = lpdf.constant
-local pdfreference = lpdf.reference
-local pdfunicode = lpdf.unicode
-local pdfverbose = lpdf.verbose
-local pdfstring = lpdf.string
-local pdfflushobject = lpdf.flushobject
-
-local pdfimmediateobj = pdf.immediateobj
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfboolean = lpdf.boolean
+local pdfconstant = lpdf.constant
+local pdfreference = lpdf.reference
+local pdfunicode = lpdf.unicode
+local pdfverbose = lpdf.verbose
+local pdfstring = lpdf.string
+local pdfflushobject = lpdf.flushobject
+local pdfimmediateobject = lpdf.immediateobject
local tobasepoints = number.tobasepoints
local variables = interfaces.variables
@@ -58,7 +57,7 @@ local function initializenegative()
Range = a,
Domain = a,
}
- local negative = pdfdictionary { Type = g, TR = pdfreference(pdfimmediateobj("stream","1 exch sub",d())) }
+ local negative = pdfdictionary { Type = g, TR = pdfreference(pdfimmediateobject("stream","1 exch sub",d())) }
local positive = pdfdictionary { Type = g, TR = pdfconstant("Identity") }
lpdf.adddocumentextgstate("GSnegative", pdfreference(pdfflushobject(negative)))
lpdf.adddocumentextgstate("GSPositive", pdfreference(pdfflushobject(positive)))
@@ -118,10 +117,10 @@ end
local function flushdocumentactions()
if opendocument then
- lpdf.addtocatalog("OpenAction",lpdf.pdfaction(opendocument))
+ lpdf.addtocatalog("OpenAction",lpdf.action(opendocument))
end
if closedocument then
- lpdf.addtocatalog("CloseAction",lpdf.pdfaction(closedocument))
+ lpdf.addtocatalog("CloseAction",lpdf.action(closedocument))
end
end
@@ -129,17 +128,17 @@ local function flushpageactions()
if openpage or closepage then
local d = pdfdictionary()
if openpage then
- d.O = lpdf.pdfaction(openpage)
+ d.O = lpdf.action(openpage)
end
if closepage then
- d.C = lpdf.pdfaction(closepage)
+ d.C = lpdf.action(closepage)
end
lpdf.addtopageattributes("AA",d)
end
end
-lpdf.registerpagefinalizer(flushpageactions)
-lpdf.registerdocumentfinalizer(flushdocumentactions)
+lpdf.registerpagefinalizer(flushpageactions,"page actions")
+lpdf.registerdocumentfinalizer(flushdocumentactions,"document actions")
--- info
@@ -189,7 +188,7 @@ local function flushjavascripts()
local name, script = t[i][1], t[i][2]
local j = pdfdictionary {
S = pdf_javascript,
- JS = pdfreference(pdfimmediateobj("stream",script)),
+ JS = pdfreference(pdfimmediateobject("stream",script)),
}
a[#a+1] = pdfstring(name)
a[#a+1] = pdfreference(pdfflushobject(j))
@@ -198,7 +197,7 @@ local function flushjavascripts()
end
end
-lpdf.registerdocumentfinalizer(flushjavascripts)
+lpdf.registerdocumentfinalizer(flushjavascripts,"javascripts")
-- -- --
@@ -288,8 +287,8 @@ local function pagespecification()
-- lpdf.addtopageattributes("ArtBox",box)
end
-lpdf.registerpagefinalizer(pagespecification)
-lpdf.registerdocumentfinalizer(documentspecification)
+lpdf.registerpagefinalizer(pagespecification,"page specification")
+lpdf.registerdocumentfinalizer(documentspecification,"document specification")
-- Page Label support ...
--
@@ -332,4 +331,4 @@ local function featurecreep()
lpdf.addtocatalog("PageLabels", pdfdictionary { Nums = list })
end
-lpdf.registerdocumentfinalizer(featurecreep)
+lpdf.registerdocumentfinalizer(featurecreep,"featurecreep")
diff --git a/tex/context/base/lpdf-pdx.lua b/tex/context/base/lpdf-pdx.lua
index 43b0b87dc..db1217c53 100644
--- a/tex/context/base/lpdf-pdx.lua
+++ b/tex/context/base/lpdf-pdx.lua
@@ -6,6 +6,10 @@ if not modules then modules = { } end modules ['lpdf-pdx'] = {
license = "see context related readme files",
}
+local trace_colorprofiles = false trackers.register("backend.colorprofiles", function(v) trace_colorprofiles = v end)
+
+local report_backends = logs.new("backends")
+
local codeinjections = backends.codeinjections -- normally it is registered
local variables = interfaces.variables
@@ -16,6 +20,7 @@ local pdfreference = lpdf.reference
local pdfflushobject = lpdf.flushobject
local pdfstring = lpdf.string
local pdfverbose = lpdf.verbose
+local pdfobject = lpdf.object
local lower, gmatch = string.lower, string.gmatch
@@ -47,9 +52,9 @@ function codeinjections.useinternalICCprofile(colorspace,filename)
local channel = channels[colorspace]
if channel and filename ~= "" then
local a = pdfdictionary { N = channel }
- profile = pdf.obj {
+ profile = pdfobject {
compresslevel = 0,
- immediate = true,
+ immediate = true, -- !
type = "stream",
file = filename,
attr = a(),
@@ -85,30 +90,51 @@ function codeinjections.useexternalICCprofile(colorspace,name,urls,checksum,vers
end
end
-local function embedprofile(colorspace,filename)
- local colorspace = lower(colorspace)
- local n = codeinjections.useinternalICCprofile(colorspace,filename)
- if n then
- local a = pdfarray {
- pdfconstant("ICCBased"),
- pdfreference(n),
- }
- lpdf.adddocumentcolorspace(prefixes[colorspace],pdfreference(pdfflushobject(a))) -- part of page /Resources
- defaults[lower(colorspace)] = filename
- end
-end
-
+local loaded = { }
function codeinjections.useICCdefaultprofile(colorspace,filename)
- defaults[lower(colorspace)] = filename
-end
-
-local function flushembeddedprofiles()
- for colorspace, filename in next, defaults do
- embedprofile(colorspace,filename)
+ local colorspace = lower(colorspace)
+ if not loaded[colorspace] then
+ local n = codeinjections.useinternalICCprofile(colorspace,filename)
+ if n then
+ local a = pdfarray {
+ pdfconstant("ICCBased"),
+ pdfreference(n),
+ }
+ -- used in page /Resources, so this must be inserted at runtime
+ lpdf.adddocumentcolorspace(prefixes[colorspace],pdfreference(pdfflushobject(a)))
+ if trace_colorprofiles then
+ report_backends("including color profile '%s' from '%s'",colorspace,filename)
+ end
+ elseif trace_colorprofiles then
+ report_backends("no color profile '%s' in '%s'",colorspace,filename)
+ end
+ loaded = true
+ elseif trace_colorprofiles then
+ report_backends("color profile '%s' is already included",colorspace)
end
end
+--~ The following is somewhat cleaner but then we need to flag that there are
+--~ color spaces set so that the page flusher does not optimize the (at that
+--~ moment) still empty array away. So, next(d_colorspaces) should then become
+--~ a different test, i.e. also on flag. I'll add that when we need more forward
+--~ referencing.
+--~
+--~ local function embedprofile = codeinjections.useICCdefaultprofile
+--~
+--~ local function flushembeddedprofiles()
+--~ for colorspace, filename in next, defaults do
+--~ embedprofile(colorspace,filename)
+--~ end
+--~ end
+--~
+--~ function codeinjections.useICCdefaultprofile(colorspace,filename)
+--~ defaults[lower(colorspace)] = filename
+--~ end
+--~
+--~ lpdf.registerdocumentfinalizer(flushembeddedprofiles,1,"embedded color profiles")
+
function codeinjections.usePDFXoutputintent(id,name,reference,outputcondition,info)
local d = {
Type = pdfconstant("OutputIntent"),
@@ -125,6 +151,9 @@ function codeinjections.usePDFXoutputintent(id,name,reference,outputcondition,in
d["DestOutputProfile"] = pdfreference(icc)
end
intents[#intents+1] = pdfreference(pdfflushobject(pdfdictionary(d)))
+ if trace_colorprofiles then
+ report_backends("adding output intent '%s' with id '%s' (entry %s)",name,id,#intents)
+ end
end
local function flushoutputintents()
@@ -133,6 +162,4 @@ local function flushoutputintents()
end
end
-
-lpdf.registerdocumentfinalizer(flushoutputintents,1)
-lpdf.registerdocumentfinalizer(flushembeddedprofiles,1)
+lpdf.registerdocumentfinalizer(flushoutputintents,2,"output intents")
diff --git a/tex/context/base/lpdf-ren.lua b/tex/context/base/lpdf-ren.lua
index e6bbd67fe..0e4e34c2a 100644
--- a/tex/context/base/lpdf-ren.lua
+++ b/tex/context/base/lpdf-ren.lua
@@ -103,8 +103,8 @@ local function flushpagelayers()
end
end
-lpdf.registerpagefinalizer (flushpagelayers)
-lpdf.registerdocumentfinalizer(flushtextlayers)
+lpdf.registerpagefinalizer (flushpagelayers,"layers")
+lpdf.registerdocumentfinalizer(flushtextlayers,"layers")
local function setlayer(what,arguments)
-- maybe just a gmatch of even better, earlier in lpeg
diff --git a/tex/context/base/lpdf-swf.lua b/tex/context/base/lpdf-swf.lua
index 9fe0cd09f..34e72f1ec 100644
--- a/tex/context/base/lpdf-swf.lua
+++ b/tex/context/base/lpdf-swf.lua
@@ -11,14 +11,15 @@ if not modules then modules = { } end modules ['lpdf-swf'] = {
local format = string.format
-local pdfconstant = lpdf.constant
-local pdfboolean = lpdf.boolean
-local pdfstring = lpdf.string
-local pdfunicode = lpdf.unicode
-local pdfdictionary = lpdf.dictionary
-local pdfarray = lpdf.array
-local pdfnull = lpdf.null
-local pdfreference = lpdf.reference
+local pdfconstant = lpdf.constant
+local pdfboolean = lpdf.boolean
+local pdfstring = lpdf.string
+local pdfunicode = lpdf.unicode
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfnull = lpdf.null
+local pdfreference = lpdf.reference
+local pdfimmediateobject = lpdf.immediateobject
function backends.pdf.helpers.insertswf(spec)
@@ -38,7 +39,7 @@ function backends.pdf.helpers.insertswf(spec)
},
}
- local fref = pdfreference(pdf.immediateobj(tostring(flash)))
+ local fref = pdfreference(pdfimmediateobject(tostring(flash)))
local configuration = pdfdictionary {
Configurations = pdfarray { fref },
@@ -50,7 +51,7 @@ function backends.pdf.helpers.insertswf(spec)
},
}
- local cref = pdfreference(pdf.immediateobj(tostring(configuration)))
+ local cref = pdfreference(pdfimmediateobject(tostring(configuration)))
local activation = pdfdictionary {
Activation = pdfdictionary {
@@ -96,7 +97,7 @@ function backends.pdf.helpers.insertswf(spec)
}
}
- local aref = pdfreference(pdf.immediateobj(tostring(activation)))
+ local aref = pdfreference(pdfimmediateobject(tostring(activation)))
local annotation = pdfdictionary {
Subtype = pdfconstant("RichMedia"),
diff --git a/tex/context/base/lpdf-tag.lua b/tex/context/base/lpdf-tag.lua
new file mode 100644
index 000000000..591def8b1
--- /dev/null
+++ b/tex/context/base/lpdf-tag.lua
@@ -0,0 +1,390 @@
+if not modules then modules = { } end modules ['lpdf-tag'] = {
+ version = 1.001,
+ comment = "companion to lpdf-tag.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, match, concat = string.format, string.match, table.concat
+local lpegmatch = lpeg.match
+local utfchar = utf.char
+
+local trace_tags = false trackers.register("structure.tags", function(v) trace_tags = v end)
+
+local report_tags = logs.new("tags")
+
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfboolean = lpdf.boolean
+local pdfconstant = lpdf.constant
+local pdfreference = lpdf.reference
+local pdfunicode = lpdf.unicode
+local pdfstring = lpdf.string
+local pdfflushobject = lpdf.flushobject
+local pdfreserveobject = lpdf.reserveobject
+local pdfpagereference = lpdf.pagereference
+
+local new_pdfliteral = nodes.pdfliteral
+
+local hlist = node.id("hlist")
+local vlist = node.id("vlist")
+local glyph = node.id("glyph")
+local glue = node.id("glue")
+local disc = node.id("disc")
+local whatsit = node.id("whatsit")
+
+local a_tagged = attributes.private('tagged')
+local a_image = attributes.private('image')
+
+local has_attribute, set_attribute, traverse_nodes, traverse_id = node.has_attribute, node.set_attribute, node.traverse, node.traverse_id
+local tosequence = nodes.tosequence
+local copy_node, slide_nodelist = node.copy, node.slide
+
+local structure_stack = { }
+local structure_kids = pdfarray()
+local structure_ref = pdfreserveobject()
+local parent_ref = pdfreserveobject()
+local root = { pref = pdfreference(structure_ref), kids = structure_kids }
+local tree = { }
+local elements = { }
+local names = pdfarray()
+local taglist = { } -- set later
+
+local colonsplitter = lpeg.splitat(":")
+local dashsplitter = lpeg.splitat("-")
+
+local add_ids = false -- true
+
+local mapping = {
+ document = "Div",
+
+ division = "Div",
+ paragraph = "P",
+ construct = "Span",
+
+ structure = "Sect",
+ structuretitle = "H",
+ structurenumber = "H",
+ structurecontent = "Div",
+
+ itemgroup = "L",
+ item = "Li",
+ itemtag = "Lbl",
+ itemcontent = "LBody",
+
+ description = "Li",
+ descriptiontag = "Lbl",
+ descriptioncontent = "LBody",
+
+ verbatimblock = "Code",
+ verbatim = "Code",
+
+ register = "Div",
+ registersection = "Div",
+ registertag = "Span",
+ registerentries = "Div",
+ registerentry = "Span",
+ registersee = "Span",
+ registerpages = "Span",
+ registerpage = "Span",
+
+ table = "Table",
+ tablerow = "TR",
+ tablecell = "TD",
+ tabulate = "Table",
+ tabulaterow = "TR",
+ tabulatecell = "TD",
+
+ list = "TOC",
+ listitem = "TOCI",
+ listtag = "Lbl",
+ listcontent = "P",
+ listdata = "P",
+ listpage = "Reference",
+
+ delimitedblock = "BlockQuote",
+ delimited = "Quote",
+ subsentence = "Span",
+
+ float = "Div",
+ floatcaption = "Caption",
+ floattag = "Span",
+ floattext = "Span",
+ floatcontent = "P",
+
+ image = "P",
+ mpgraphic = "P",
+
+ formulaset = "Div",
+ formula = "Div",
+ formulatag = "Span",
+ formulacontent = "P",
+ subformula = "Div",
+
+ link = "Link",
+
+ math = "Div",
+ mn = "Span",
+ mi = "Span",
+ mo = "Span",
+ ms = "Span",
+ mrow = "Span",
+ msubsup = "Span",
+ msub = "Span",
+ msup = "Span",
+ merror = "Span",
+ munderover = "Span",
+ munder = "Span",
+ mover = "Span",
+ mtext = "Span",
+ mfrac = "Span",
+ mroot = "Span",
+ msqrt = "Span",
+}
+
+local usedmapping = { }
+local usedlabels = { }
+
+function backends.codeinjections.mapping()
+ return mapping -- future versions may provide a copy
+end
+
+function backends.codeinjections.maptag(original,target)
+ mapping[original] = target
+end
+
+local function finishstructure()
+ if #structure_kids > 0 then
+ local nums = pdfarray()
+ for i=1,#tree do
+ nums[#nums+1] = i-1
+ nums[#nums+1] = pdfreference(pdfflushobject(tree[i]))
+ end
+ local parenttree = pdfdictionary {
+ Nums = nums
+ }
+ -- we need to split names into smaller parts (e.g. alphabetic or so)
+ if add_ids then
+ local kids = pdfdictionary {
+ Limits = pdfarray { names[1], names[#names-1] },
+ Names = names,
+ }
+ local idtree = pdfdictionary {
+ Kids = pdfarray { pdfreference(pdfflushobject(kids)) },
+ }
+ end
+ --
+ local rolemap = pdfdictionary()
+ for k, v in next, usedmapping do
+ k = usedlabels[k] or k
+ rolemap[k] = pdfconstant(mapping[k] or "Span") -- or "Div"
+ end
+ local structuretree = pdfdictionary {
+ Type = pdfconstant("StructTreeRoot"),
+ K = pdfreference(pdfflushobject(structure_kids)),
+ ParentTree = pdfreference(pdfflushobject(parent_ref,parenttree)),
+ IDTree = (add_ids and pdfreference(pdfflushobject(idtree))) or nil,
+ RoleMap = rolemap,
+ }
+ pdfflushobject(structure_ref,structuretree)
+ lpdf.addtocatalog("StructTreeRoot",pdfreference(structure_ref))
+ --
+ local markinfo = pdfdictionary {
+ Marked = pdfboolean(true),
+ -- UserProperties = pdfboolean(true),
+ -- Suspects = pdfboolean(true),
+ }
+ lpdf.addtocatalog("MarkInfo",pdfreference(pdfflushobject(markinfo)))
+ --
+ for fulltag, element in next, elements do
+ pdfflushobject(element.knum,element.kids)
+ end
+ end
+end
+
+lpdf.registerdocumentfinalizer(finishstructure,"document structure")
+
+local index, pageref, pagenum, list = 0, nil, 0, nil
+
+local pdf_mcr = pdfconstant("MCR")
+local pdf_struct_element = pdfconstant("StructElem")
+
+local function initializepage()
+ index = 0
+ pagenum = tex.count.realpageno
+ pageref = pdfreference(pdfpagereference(pagenum))
+ list = pdfarray()
+ tree[pagenum] = list -- we can flush after done, todo
+end
+
+local function finishpage()
+ -- flush what can be flushed
+ lpdf.addtopageattributes("StructParents",pagenum-1)
+end
+
+-- here we can flush and free elements that are finished
+
+local function makeelement(fulltag,parent)
+ local tag, n = lpegmatch(dashsplitter,fulltag)
+ local tg, detail = lpegmatch(colonsplitter,tag)
+ local k, r = pdfarray(), pdfreserveobject()
+ usedmapping[tg] = true
+ tg = usedlabels[tg] or tg
+ local d = pdfdictionary {
+ Type = pdf_struct_element,
+ S = pdfconstant(tg),
+ ID = (add_ids and fulltag) or nil,
+ T = detail and detail or nil,
+ P = parent.pref,
+ Pg = pageref,
+ K = pdfreference(r),
+--~ Alt = " Who cares ",
+--~ ActualText = " Hi Hans ",
+ }
+ local s = pdfreference(pdfflushobject(d))
+ if add_ids then
+ names[#names+1] = fulltag
+ names[#names+1] = s
+ end
+ local kids = parent.kids
+ kids[#kids+1] = s
+ elements[fulltag] = { tag = tag, pref = s, kids = k, knum = r, pnum = pagenum }
+end
+
+local function makecontent(parent,start,stop,slist,id)
+ local tag, kids = parent.tag, parent.kids
+ local last = index
+ if id == "image" then
+ local d = pdfdictionary {
+ Type = pdf_mcr,
+ Pg = pageref,
+ MCID = last,
+ Alt = "image",
+ }
+ kids[#kids+1] = d
+ elseif pagenum == parent.pnum then
+ kids[#kids+1] = last
+ else
+ local d = pdfdictionary {
+ Type = pdf_mcr,
+ Pg = pageref,
+ MCID = last,
+ }
+ -- kids[#kids+1] = pdfreference(pdfflushobject(d))
+ kids[#kids+1] = d
+ end
+ --
+ local bliteral = new_pdfliteral(format("/%s <</MCID %s>>BDC",tag,last))
+ local prev = start.prev
+ if prev then
+ prev.next, bliteral.prev = bliteral, prev
+ end
+ start.prev, bliteral.next = bliteral, start
+ if slist and slist.list == start then
+ slist.list = bliteral
+ elseif not prev then
+ report_tags("this can't happen: injection in front of nothing")
+ end
+ --
+ local eliteral = new_pdfliteral("EMC")
+ local next = stop.next
+ if next then
+ next.prev, eliteral.next = eliteral, next
+ end
+ stop.next, eliteral.prev = eliteral, stop
+ --
+ index = index + 1
+ list[index] = parent.pref
+ return bliteral, eliteral
+end
+
+-- -- --
+
+local level, last, ranges, range = 0, nil, { }, { }
+
+local function collectranges(head,list)
+ for n in traverse_nodes(head) do
+ local id = n.id -- 14: image, 8: literal (mp)
+ if id == glyph then
+ local at = has_attribute(n,a_tagged)
+ if not at then
+ range = nil
+ elseif last ~= at then
+ range = { at, "glyph", n, n, list } -- attr id start stop list
+ ranges[#ranges+1] = range
+ last = at
+ elseif range then
+ range[4] = n -- stop
+ end
+ elseif id == hlist or id == vlist then
+ local at = has_attribute(n,a_image)
+ if at then
+ local at = has_attribute(n,a_tagged)
+ if not at then
+ range = nil
+ else
+ ranges[#ranges+1] = { at, "image", n, n, list } -- attr id start stop list
+ end
+ last = nil
+ else
+ slide_nodelist(n.list) -- temporary hack till math gets slided (tracker item)
+ collectranges(n.list,n)
+ end
+ end
+ end
+end
+
+function backends.nodeinjections.addtags(head)
+ -- no need to adapt head, as we always operate on lists
+ level, last, ranges, range = 0, nil, { }, { }
+ initializepage()
+ collectranges(head)
+ if trace_tags then
+ for i=1,#ranges do
+ local range = ranges[i]
+ local attr, id, start, stop = range[1], range[2], range[3], range[4]
+ local tags = taglist[attr]
+ if tags then
+ report_tags("%s => %s : %05i %s",tosequence(start,start),tosequence(stop,stop),attr,concat(tags," "))
+ end
+ end
+ end
+ for i=1,#ranges do
+ local range = ranges[i]
+ local attr, id, start, stop, list = range[1], range[2], range[3], range[4], range[5]
+ local tags = taglist[attr]
+ local prev = root
+ local noftags, tag = #tags, nil
+ for j=1,noftags do
+ local tag = tags[j]
+ if not elements[tag] then
+ makeelement(tag,prev)
+ end
+ prev = elements[tag]
+ end
+ local b, e = makecontent(prev,start,stop,list,id)
+ if start == head then
+ report_tags("this can't happen: parent list gets tagged")
+ head = b
+ end
+ end
+ finishpage()
+ -- can be separate feature
+ --
+ -- injectspans(head) -- does to work yet
+ --
+ return head, true
+end
+
+function backends.codeinjections.enabletags(tg,lb)
+ taglist = tg
+ usedlabels = lb
+ structure.tags.handler = backends.nodeinjections.addtags
+ tasks.enableaction("shipouts","structure.tags.handler")
+ tasks.enableaction("shipouts","nodes.accessibility.handler")
+ tasks.enableaction("math","noads.add_tags")
+ if trace_tags then
+ report_tags("enabling structure tags")
+ end
+end
diff --git a/tex/context/base/lpdf-u3d.lua b/tex/context/base/lpdf-u3d.lua
index f7a62c6c9..1bb99dc21 100644
--- a/tex/context/base/lpdf-u3d.lua
+++ b/tex/context/base/lpdf-u3d.lua
@@ -16,19 +16,18 @@ if not modules then modules = { } end modules ['lpdf-u3d'] = {
local format, find = string.format, string.find
local cos, sin, sqrt, pi, atan2, abs = math.cos, math.sin, math.sqrt, math.pi, math.atan2, math.abs
-local pdfconstant = lpdf.constant
-local pdfboolean = lpdf.boolean
-local pdfnumber = lpdf.number
-local pdfunicode = lpdf.unicode
-local pdfdictionary = lpdf.dictionary
-local pdfarray = lpdf.array
-local pdfnull = lpdf.null
-local pdfreference = lpdf.reference
-
-local pdfimmediateobj = pdf.immediateobj
-
-local checkedkey = lpdf.checkedkey
-local limited = lpdf.limited
+local pdfconstant = lpdf.constant
+local pdfboolean = lpdf.boolean
+local pdfnumber = lpdf.number
+local pdfunicode = lpdf.unicode
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfnull = lpdf.null
+local pdfreference = lpdf.reference
+local pdfimmediateobject = lpdf.immediateobject
+
+local checkedkey = lpdf.checkedkey
+local limited = lpdf.limited
local schemes = table.tohash {
"Artwork", "None", "White", "Day", "Night", "Hard",
@@ -388,12 +387,12 @@ function backends.pdf.helpers.insert3d(spec) -- width, height, factor, display,
if js then
local jsref = stored_js[js]
if not jsref then
- jsref = pdfimmediateobj("streamfile",js)
+ jsref = pdfimmediateobject("streamfile",js)
stored_js[js] = jsref
end
attr.OnInstantiate = pdfreference(jsref)
end
- stored_3d[label] = pdfimmediateobj("streamfile",foundname,attr())
+ stored_3d[label] = pdfimmediateobject("streamfile",foundname,attr())
stream = 1
else
stream = stream + 1
@@ -456,7 +455,7 @@ function backends.pdf.helpers.insert3d(spec) -- width, height, factor, display,
},
ProcSet = pdfarray { pdfconstant("PDF"), pdfconstant("ImageC") },
}
- local pwd = pdfimmediateobj(
+ local pwd = pdfimmediateobject(
"stream",
format("q /GS gs %s 0 0 %s 0 0 cm /IM Do Q",
factor*width,factor*height),
diff --git a/tex/context/base/lpdf-wid.lua b/tex/context/base/lpdf-wid.lua
index 40a81e7d4..323e3c79d 100644
--- a/tex/context/base/lpdf-wid.lua
+++ b/tex/context/base/lpdf-wid.lua
@@ -16,20 +16,20 @@ local registrations = backends.pdf.registrations
local executers = jobreferences.executers
local variables = interfaces.variables
-local pdfconstant = lpdf.constant
-local pdfdictionary = lpdf.dictionary
-local pdfarray = lpdf.array
-local pdfreference = lpdf.reference
-local pdfunicode = lpdf.unicode
-local pdfstring = lpdf.string
-local pdfcolorspec = lpdf.colorspec
-local pdfflushobject = lpdf.flushobject
-local pdfreserveobject = lpdf.reserveobject
-
-local pdfreserveobj = pdf.reserveobj
-local pdfimmediateobj = pdf.immediateobj
-
-local pdfannotation = nodes.pdfannotation
+local pdfconstant = lpdf.constant
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfreference = lpdf.reference
+local pdfunicode = lpdf.unicode
+local pdfstring = lpdf.string
+local pdfcolorspec = lpdf.colorspec
+local pdfflushobject = lpdf.flushobject
+local pdfreserveobject = lpdf.reserveobject
+local pdfreserveannotation = lpdf.reserveobject
+local pdfimmediateobject = lpdf.immediateobject
+local pdfpagereference = lpdf.pagereference
+
+local pdfannotation_node = nodes.pdfannotation
local hpack_node, write_node = node.hpack, node.write
@@ -135,10 +135,10 @@ function codeinjections.registercomment(specification)
Parent = pdfreference(nd),
}
d.Popup = pdfreference(nc)
- texbox["commentboxone"] = hpack_node(pdfannotation(0,0,0,d(),nd)) -- current dir
- texbox["commentboxtwo"] = hpack_node(pdfannotation(specification.width,specification.height,0,c(),nc)) -- current dir
+ texbox["commentboxone"] = hpack_node(pdfannotation_node(0,0,0,d(),nd)) -- current dir
+ texbox["commentboxtwo"] = hpack_node(pdfannotation_node(specification.width,specification.height,0,c(),nc)) -- current dir
else
- texbox["commentboxone"] = hpack_node(pdfannotation(0,0,0,d())) -- current dir
+ texbox["commentboxone"] = hpack_node(pdfannotation_node(0,0,0,d())) -- current dir
texbox["commentboxtwo"] = nil
end
end
@@ -160,7 +160,7 @@ function codeinjections.embedfile(filename)
else
local basename = file.basename(filename)
local a = pdfdictionary { Type = pdfconstant("EmbeddedFile") }
- local f = pdfimmediateobj("streamfile",filename,a())
+ local f = pdfimmediateobject("streamfile",filename,a())
local d = pdfdictionary {
Type = pdfconstant("Filespec"),
F = pdfstring(newname or basename),
@@ -211,7 +211,7 @@ function codeinjections.attachfile(specification)
local width = specification.width or 0
local height = specification.height or 0
local depth = specification.depth or 0
- write_node(pdfannotation(width,height,depth,d()))
+ write_node(pdfannotation_node(width,height,depth,d()))
end
function codeinjections.attachmentid(filename)
@@ -255,20 +255,20 @@ local function insertrenderingwindow(label,width,height,specification)
local actions = nil
if openpage or closepage then
actions = pdfdictionary {
- PO = (openpage and lpdf.pdfaction(openpage )) or nil,
- PC = (closepage and lpdf.pdfaction(closepage)) or nil,
+ PO = (openpage and lpdf.action(openpage )) or nil,
+ PC = (closepage and lpdf.action(closepage)) or nil,
}
end
local page = tonumber(specification.page) or texcount.realpageno
local d = pdfdictionary {
Subtype = pdfconstant("Screen"),
- P = pdfreference(tex.pdfpageref(page)),
+ P = pdfreference(pdfpagereference(page)),
A = mf[label],
Border = pdfarray { 0, 0, 0 } ,
AA = actions,
}
- local r = pdfreserveobj("annot")
- write_node(pdfannotation(width,height,0,d(),r)) -- save ref
+ local r = pdfreserveannotation()
+ write_node(pdfannotation_node(width,height,0,d(),r)) -- save ref
return pdfreference(r)
end
diff --git a/tex/context/base/lpdf-xmp.lua b/tex/context/base/lpdf-xmp.lua
index c8e7b2b57..79f732be0 100644
--- a/tex/context/base/lpdf-xmp.lua
+++ b/tex/context/base/lpdf-xmp.lua
@@ -14,6 +14,8 @@ local trace_xmp = false trackers.register("backend.xmp", function(v) trace_xmp
local pdfdictionary = lpdf.dictionary
local pdfconstant = lpdf.constant
+local pdfreference = lpdf.reference
+local pdfobject = lpdf.object
-- i wonder why this begin end is empty / w (no time now to look into it)
@@ -119,7 +121,6 @@ end
local t = { } for i=1,24 do t[i] = random() end
local function flushxmpinfo()
-
commands.freezerandomseed(os.clock()) -- hack
local t = { } for i=1,24 do t[i] = char(96 + random(26)) end
@@ -144,22 +145,25 @@ local function flushxmpinfo()
texio.write("log","\n% ",(gsub(blob,"[\r\n]","\n%% ")),"\n")
end
blob = format(xpacket,packetid,blob)
- if tex.pdfcompresslevel > 0 then
+ if not verbose and tex.pdfcompresslevel > 0 then
blob = gsub(blob,">%s+<","><")
end
- local r = pdf.obj {
+ local r = pdfobject {
immediate = true,
compresslevel = 0,
type = "stream",
string = blob,
attr = md(),
}
- lpdf.addtocatalog("Metadata",lpdf.reference(r))
+ lpdf.addtocatalog("Metadata",pdfreference(r))
commands.defrostrandomseed() -- hack
-
end
-- his will be enabled when we can inhibit compression for a stream at the lua end
-lpdf.registerdocumentfinalizer(flushxmpinfo,1)
+lpdf.registerdocumentfinalizer(flushxmpinfo,1,"metadata")
+
+directives.register("backend.verbosexmp", function(v)
+ verbose = v
+end)
diff --git a/tex/context/base/luat-cnf.lua b/tex/context/base/luat-cnf.lua
index 054de7c81..8be5dc7c3 100644
--- a/tex/context/base/luat-cnf.lua
+++ b/tex/context/base/luat-cnf.lua
@@ -116,7 +116,7 @@ local function makestub()
io.savedata(name,format("%s\n\n%s",concat(t,"\n"),format(stub,firsttable)))
end
-lua.registerfinalizer(makestub)
+lua.registerfinalizer(makestub,"create stub file")
-- to be moved here:
--
diff --git a/tex/context/base/luat-cod.lua b/tex/context/base/luat-cod.lua
index 4a1a3d6f0..a5239e7ae 100644
--- a/tex/context/base/luat-cod.lua
+++ b/tex/context/base/luat-cod.lua
@@ -51,15 +51,19 @@ end
local finalizers = { }
-function lua.registerfinalizer(f)
+function lua.registerfinalizer(f,comment)
if type(f) == "function"then
- finalizers[#finalizers+1] = f
+ finalizers[#finalizers+1] = { action = f, comment = comment }
end
end
-function lua.finalize()
+function lua.finalize(logger)
for i=1,#finalizers do
- finalizers[i]()
+ local finalizer = finalizers[i]
+ finalizer.action()
+ if logger then
+ logger("finalizing lua", "action: %s",finalizer.comment)
+ end
end
end
diff --git a/tex/context/base/luat-cod.mkiv b/tex/context/base/luat-cod.mkiv
index 94d245a3f..5104f3e6b 100644
--- a/tex/context/base/luat-cod.mkiv
+++ b/tex/context/base/luat-cod.mkiv
@@ -61,6 +61,6 @@
\registerctxluafile{luat-cod}{1.001}
-\everydump\expandafter{\the\everydump\ctxlua{lua.finalize()}}
+% \everydump\expandafter{\the\everydump\ctxlua{lua.finalize()}}
\endinput
diff --git a/tex/context/base/luat-ini.mkiv b/tex/context/base/luat-ini.mkiv
index b7a0eb516..63cf02d01 100644
--- a/tex/context/base/luat-ini.mkiv
+++ b/tex/context/base/luat-ini.mkiv
@@ -243,4 +243,23 @@
\def\luaconditional#1{\ifcase#1tru\else fals\fi e}
+%D Goodie:
+%D
+%D \starttyping
+%D \ctxluacode{context("%0.5f",1/3)}
+%D \stoptyping
+
+\long\def\ctxluacode
+ {\begingroup
+ \obeylualines
+ \obeyluatokens
+ \catcode`\{\plusone
+ \catcode`\}\plustwo
+ \afterassignment\doctxluacode
+ \scratchtoks=}
+
+\def\doctxluacode
+ {\normalexpanded{\endgroup\noexpand\directlua\zerocount\expandafter{\the\scratchtoks}}}
+
+
\protect \endinput
diff --git a/tex/context/base/luat-run.lua b/tex/context/base/luat-run.lua
index d33cbddd6..f40428d37 100644
--- a/tex/context/base/luat-run.lua
+++ b/tex/context/base/luat-run.lua
@@ -8,6 +8,10 @@ if not modules then modules = { } end modules ['luat-run'] = {
local format, rpadd = string.format, string.rpadd
+local trace_lua_dump = false trackers .register("system.dump", function(v) trace_lua_dump = v end)
+
+local report_lua_dump = logs.new("lua dump actions")
+
luatex = luatex or { }
local start_actions = { }
@@ -59,6 +63,10 @@ end
function luatex.report_output_log()
end
+function luatex.pre_dump_actions()
+ lua.finalize(trace_lua_dump and report_lua_dump or nil)
+end
+
-- this can be done later
callbacks.register('start_run', luatex.start_run, "actions performed at the beginning of a run")
@@ -72,3 +80,5 @@ callbacks.register('stop_page_number', luatex.stop_shipout_page, "actions
callbacks.register('process_input_buffer', false, "actions performed when reading data")
callbacks.register('process_output_buffer', false, "actions performed when writing data")
+
+callbacks.register("pre_dump", luatex.pre_dump_actions, "lua related finalizers called before we dump the format") -- comes after \everydump
diff --git a/tex/context/base/luat-sto.lua b/tex/context/base/luat-sto.lua
index 4d7af73e4..98a14e35f 100644
--- a/tex/context/base/luat-sto.lua
+++ b/tex/context/base/luat-sto.lua
@@ -52,7 +52,7 @@ local function finalize() -- we can prepend the string with "evaluate:"
end
end
-lua.registerfinalizer(finalize)
+lua.registerfinalizer(finalize,"evaluate storage")
local function dump()
for i=1,#data do
@@ -86,7 +86,7 @@ local function dump()
end
end
-lua.registerfinalizer(dump)
+lua.registerfinalizer(dump,"dump storage")
-- we also need to count at generation time (nicer for message)
diff --git a/tex/context/base/math-ini.mkiv b/tex/context/base/math-ini.mkiv
index c960e8d7c..729e10443 100644
--- a/tex/context/base/math-ini.mkiv
+++ b/tex/context/base/math-ini.mkiv
@@ -46,11 +46,23 @@
\registerctxluafile{math-vfu}{1.001}
\registerctxluafile{math-map}{1.001}
\registerctxluafile{math-noa}{1.001}
+\registerctxluafile{math-tag}{1.001}
\definesystemattribute[mathalphabet] \chardef\mathalphabetattribute \dogetattributeid{mathalphabet}
\definesystemattribute[mathsize] \chardef\mathsizeattribute \dogetattributeid{mathsize}
\definesystemattribute[mathpunctuation] \chardef\mathpunctuationattribute \dogetattributeid{mathpunctuation}
\definesystemattribute[mathgreek] \chardef\mathgreekattribute \dogetattributeid{mathgreek}
+\definesystemattribute[mathalternate] \chardef\mathalternateattribute \dogetattributeid{mathalternate}
+
+% experiment
+
+% Normally this is applied to only one character.
+%
+% $ABC$ $\cal ABC$ $\mathaltcal ABC$
+
+\def\mathalternate#1{\ctxlua{mathematics.setalternate(0,"#1")}} % fam 0
+
+\def\mathaltcal{\mathalternate{cal}\cal} % ss01 in xits
% todo: only in mmode
diff --git a/tex/context/base/math-noa.lua b/tex/context/base/math-noa.lua
index d8c6b2b20..2b4f9b6fa 100644
--- a/tex/context/base/math-noa.lua
+++ b/tex/context/base/math-noa.lua
@@ -9,6 +9,8 @@ if not modules then modules = { } end modules ['math-noa'] = {
-- beware: this is experimental code and there will be a more
-- generic (attribute value driven) interface too but for the
-- moment this is ok
+--
+-- we will also make dedicated processors (faster)
local utf = unicode.utf8
@@ -29,19 +31,19 @@ local trace_analyzing = false trackers.register("math.analyzing", function(v)
local report_noads = logs.new("mathematics")
-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
+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:
--
@@ -337,6 +339,76 @@ function noads.respace_characters(head,style,penalties)
return true
end
+-- math alternates
+
+function fonts.initializers.common.mathalternates(tfmdata)
+ local goodies = tfmdata.goodies
+ if goodies then
+ for i=1,#goodies do
+ -- first one counts
+ -- we can consider sharing the attributes ... todo (only once scan)
+ local mathgoodies = goodies[i].mathematics
+ local alternates = mathgoodies and mathgoodies.alternates
+ if alternates then
+ local lastattribute, attributes = 0, { }
+ for k, v in next, alternates do
+ lastattribute = lastattribute + 1
+ v.attribute = lastattribute
+ attributes[lastattribute] = v
+ end
+ tfmdata.shared.mathalternates = alternates -- to be checked if shared is ok here
+ tfmdata.shared.mathalternatesattributes = attributes -- to be checked if shared is ok here
+ return
+ end
+ end
+ end
+end
+
+fonts.otf.tables.features['mathalternates'] = 'Additional math alternative shapes'
+
+fonts.otf.features.register('mathalternates',true)
+table.insert(fonts.triggers,"mathalternates")
+
+fonts.initializers.base.otf.mathalternates = fonts.initializers.common.mathalternates
+fonts.initializers.node.otf.mathalternates = fonts.initializers.common.mathalternates
+
+local get_alternate = fonts.otf.get_alternate
+
+local mathalternate = attributes.private("mathalternate")
+
+local alternate = { } -- noads.processors.alternate = alternate
+
+function mathematics.setalternate(fam,tag)
+ local id = font_of_family(fam)
+ local tfmdata = fontdata[id]
+ local mathalternates = tfmdata.shared.mathalternates
+ if mathalternates then
+ local m = mathalternates[tag]
+ tex.attribute[mathalternate] = m and m.attribute or attributes.unsetvalue
+ end
+end
+
+alternate[math_char] = function(pointer)
+ local a = has_attribute(pointer,mathalternate)
+ if a and a > 0 then
+ set_attribute(pointer,mathalternate,0)
+ local tfmdata = fontdata[font_of_family(pointer.fam)] -- we can also have a famdata
+ local mathalternatesattributes = tfmdata.shared.mathalternatesattributes
+ if mathalternatesattributes then
+ local what = mathalternatesattributes[a]
+ local alt = get_alternate(tfmdata,pointer.char,what.feature,what.value)
+ if alt then
+ pointer.char = alt
+ end
+ end
+ end
+end
+
+function noads.check_alternates(head,style,penalties)
+ process(head,alternate)
+ return true
+end
+
-- the normal builder
function noads.mlist_to_hlist(head,style,penalties)
diff --git a/tex/context/base/math-tag.lua b/tex/context/base/math-tag.lua
new file mode 100644
index 000000000..7180435f5
--- /dev/null
+++ b/tex/context/base/math-tag.lua
@@ -0,0 +1,247 @@
+if not modules then modules = { } end modules ['math-tag'] = {
+ version = 1.001,
+ comment = "companion to math-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local has_attribute = nodes.has_attribute
+local set_attribute = nodes.set_attribute
+local set_attributes = nodes.set_attributes
+
+local traverse_nodes = node.traverse
+
+local math_noad = node.id("noad") -- 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 hlist = node.id("hlist")
+local vlist = node.id("vlist")
+local glyph = node.id("glyph")
+
+local a_tagged = attributes.private('tagged')
+
+local start_tagged = structure.tags.start
+local stop_tagged = structure.tags.stop
+local chardata = characters.data
+
+local process
+
+local function processsubsup(start)
+ local nucleus, sup, sub = start.nucleus, start.sup, start.sub
+ if sub then
+ if sup then
+ set_attribute(start,a_tagged,start_tagged("msubsup"))
+ process(nucleus)
+ process(sup)
+ process(sub)
+ stop_tagged()
+ else
+ set_attribute(start,a_tagged,start_tagged("msub"))
+ process(nucleus)
+ process(sub)
+ stop_tagged()
+ end
+ elseif sup then
+ set_attribute(start,a_tagged,start_tagged("msup"))
+ process(nucleus)
+ process(sup)
+ stop_tagged()
+ else
+ process(nucleus)
+ end
+end
+
+process = function(start) -- we cannot use the processor as we have no finalizers (yet)
+ while start do
+ local id = start.id
+ if id == math_char then
+ -- check for code
+ local ch = chardata[start.char]
+ local mc = ch and ch.mathclass
+ if mc == "number" then
+ set_attribute(start,a_tagged,start_tagged("mn"))
+ elseif mc == "variable" or not mc then -- variable is default
+ set_attribute(start,a_tagged,start_tagged("mi"))
+ else
+ set_attribute(start,a_tagged,start_tagged("mo"))
+ end
+ stop_tagged()
+ break
+ elseif id == math_text_char then
+ -- check for code
+ set_attribute(start,a_tagged,start_tagged("ms"))
+ stop_tagged()
+ break
+ elseif id == math_delim then
+ -- check for code
+ set_attribute(start,a_tagged,start_tagged("mo"))
+ stop_tagged()
+ break
+ elseif id == math_style then
+ -- has a next
+ elseif id == math_noad then
+ processsubsup(start)
+ elseif id == math_box or id == hlist or id == vlist then
+ -- keep an eye on math_box and see what ends up in there
+ local attr = has_attribute(start,a_tagged)
+ local text = start_tagged("mtext")
+ set_attribute(start,a_tagged,text)
+ local list = start.list
+ if not list then
+ -- empty list
+ elseif not attr then
+ -- box comes from strange place
+ set_attributes(list,a_tagged,text)
+ else
+ -- Beware, the first node in list is the actual list so we definitely
+ -- need to nest. This approach is a hack, maybe I'll make a proper
+ -- nesting feature to deal with this at another level. Here we just
+ -- fake structure by enforcing the inner one.
+ local taglist = structure.tags.taglist
+ local tagdata = taglist[attr]
+ local common = #tagdata + 1
+ local function runner(list) -- quite inefficient
+ local cache = { } -- we can have nested unboxed mess so best local to runner
+ for n in traverse_nodes(list) do
+ local id = n.id
+ if id == hlist or id == vlist then
+ runner(n.list)
+ elseif id == glyph then
+ local aa = has_attribute(n,a_tagged) -- only glyph needed
+ if aa then
+ local ac = cache[aa]
+ if not ac then
+ local tagdata = taglist[aa]
+ local extra = #tagdata
+ if common <= extra then
+ for i=common,extra do
+ ac = start_tagged(tagdata[i]) -- can be made faster
+ end
+ for i=common,extra do
+ stop_tagged() -- can be made faster
+ end
+ else
+ ac = text
+ end
+ cache[aa] = ac
+ end
+ set_attribute(n,a_tagged,ac)
+ else
+ set_attribute(n,a_tagged,text)
+ end
+ end
+ end
+ end
+ runner(list)
+ end
+ stop_tagged()
+ elseif id == math_sub then
+ local list = start.list
+ if list then
+ set_attribute(start,a_tagged,start_tagged("mrow"))
+ process(list)
+ stop_tagged()
+ end
+ elseif id == math_fraction then
+ local num, denom, left, right = start.num, start.denom, start.left, start.right
+ if left then
+ set_attribute(left,a_tagged,start_tagged("mo"))
+ process(left)
+ stop_tagged()
+ end
+ set_attribute(start,a_tagged,start_tagged("mfrac"))
+ process(num)
+ process(denom)
+ stop_tagged()
+ if right then
+ set_attribute(right,a_tagged,start_tagged("mo"))
+ process(right)
+ stop_tagged()
+ end
+ elseif id == math_choice then
+ local display, text, script, scriptscript = start.display, start.text, start.script, start.scriptscript
+ if display then
+ process(display)
+ end
+ if text then
+ process(text)
+ end
+ if script then
+ process(script)
+ end
+ if scriptscript then
+ process(scriptscript)
+ end
+ elseif id == math_fence then
+ local delim = start.delim
+ if delim then
+ set_attribute(start,a_tagged,start_tagged("mo"))
+ process(delim)
+ stop_tagged()
+ end
+ elseif id == math_radical then
+ local left, degree = start.left, start.degree
+ if left then
+ process(left) -- mrow needed ?
+ end
+ if degree then
+ set_attribute(start,a_tagged,start_tagged("mroot"))
+ processsubsup(start)
+ process(degree)
+ stop_tagged()
+ else
+ set_attribute(start,a_tagged,start_tagged("msqrt"))
+ processsubsup(start)
+ stop_tagged()
+ end
+ elseif id == math_accent then
+ local accent, bot_accent = start.accent, start.bot_accent
+ if bot_accent then
+ if accent then
+ set_attribute(start,a_tagged,start_tagged("munderover"))
+ process(accent)
+ processsubsup(start)
+ process(bot_accent)
+ stop_tagged()
+ else
+ set_attribute(start,a_tagged,start_tagged("munder"))
+ processsubsup(start)
+ process(bot_accent)
+ stop_tagged()
+ end
+ elseif accent then
+ set_attribute(start,a_tagged,start_tagged("mover"))
+ process(accent)
+ processsubsup(start)
+ stop_tagged()
+ else
+ processsubsup(start)
+ end
+ else
+ set_attribute(start,a_tagged,start_tagged("merror"))
+ stop_tagged()
+ end
+ start = start.next
+ end
+end
+
+function noads.add_tags(head,style,penalties)
+ set_attribute(head,a_tagged,start_tagged("math"))
+ set_attribute(head,a_tagged,start_tagged("mrow"))
+ process(head)
+ stop_tagged()
+ stop_tagged()
+ return true
+end
diff --git a/tex/context/base/mlib-pdf.mkiv b/tex/context/base/mlib-pdf.mkiv
index 2681b0810..2e098730e 100644
--- a/tex/context/base/mlib-pdf.mkiv
+++ b/tex/context/base/mlib-pdf.mkiv
@@ -26,7 +26,8 @@
\xdef\MPheight{\the\dimexpr#4\onebasepoint-#2\onebasepoint\relax}}
\def\startMPLIBtoPDF#1#2#3#4% watch the transparency reset
- {\naturalhbox\bgroup
+ {\dostarttagged\t!mpgraphic\empty
+ \naturalhbox attr \imageattribute 1 \bgroup
\doactivatecolor\s!black\forcecolorhack
\MPLIBboundingbox{#1}{#2}{#3}{#4}%
%\forgetall % done already elsewhere
@@ -52,7 +53,8 @@
\wd\scratchbox\MPwidth
\ht\scratchbox\MPheight
\dopackageMPgraphic\scratchbox
- \egroup}
+ \egroup
+ \dostoptagged}
% \def\MPLIBtextext#1#2#3#4#5%
% {\begingroup
diff --git a/tex/context/base/mlib-run.lua b/tex/context/base/mlib-run.lua
index 0467498d0..a119b0836 100644
--- a/tex/context/base/mlib-run.lua
+++ b/tex/context/base/mlib-run.lua
@@ -41,9 +41,12 @@ local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming
metapost = metapost or { }
-metapost.showlog = false
-metapost.lastlog = ""
-metapost.texerrors = false
+metapost.showlog = false
+metapost.lastlog = ""
+metapost.texerrors = false
+metapost.exectime = metapost.exectime or { } -- hack
+
+local mplibone = tonumber(mplib.version()) <= 1.50
directives.register("mplib.texerrors", function(v) metapost.texerrors = v end)
@@ -63,69 +66,6 @@ end
metapost.finder = finder
-metapost.parameters = {
- hash_size = 100000,
- main_memory = 4000000,
- max_in_open = 50,
- param_size = 100000,
-}
-
-metapost.exectime = metapost.exectime or { } -- hack
-
-local preamble = [[
-boolean mplib; string mp_parent_version;
-mplib := true;
-mp_parent_version := "%s";
-input %s ; dump ;
-]]
-
-function metapost.make(name, target, version)
- 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.removesuffix(target),
- }
- ) )
- if mpx then
- starttiming(metapost.exectime)
- local result = mpx:execute(format(preamble,version or "unknown",name))
- stoptiming(metapost.exectime)
- mpx:finish()
- end
- stoptiming(mplib)
-end
-
-function metapost.load(name)
- starttiming(mplib)
- local mpx = mplib.new ( table.merged (
- metapost.parameters,
- {
- ini_version = false,
- mem_name = file.replacesuffix(name,"mem"),
- find_file = finder,
- -- job_name = "mplib",
- }
- ) )
- local result
- if not mpx then
- result = { status = 99, error = "out of memory"}
- end
- stoptiming(mplib)
- return mpx, result
-end
-
-function metapost.unload(mpx)
- starttiming(mplib)
- if mpx then
- mpx:finish()
- end
- stoptiming(mplib)
-end
-
function metapost.reporterror(result)
if not result then
report_mplib("mp error: no result object returned")
@@ -149,90 +89,148 @@ function metapost.reporterror(result)
return true
end
---~ function metapost.checkformat(mpsinput)
---~ local mpsversion = environment.version or "unset version"
---~ local mpsinput = file.addsuffix(mpsinput or "metafun", "mp")
---~ local 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 "") -- to be made dynamic
---~ if pth ~= "" then
---~ mpsformat = file.join(pth,mpsformat)
---~ end
---~ if lfs.isfile(mpsformat) then
---~ 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 ;")
---~ if not result.log then
---~ metapost.reporterror(result)
---~ else
---~ local version = match(result.log,">> *(.-)[\n\r]") or "unknown"
---~ version = gsub(version,"[\'\"]","")
---~ if version ~= mpsversion then
---~ commands.writestatus("mplib","version mismatch: %s <> %s", version or "unknown", mpsversion)
---~ else
---~ return mpx
---~ end
---~ end
---~ else
---~ commands.writestatus("mplib","error in loading '%s' from '%s'", mpsinput, mpsformat)
---~ metapost.reporterror(result)
---~ end
---~ end
---~ commands.writestatus("mplib","making '%s' into '%s'", mpsinput, mpsformat)
---~ metapost.make(mpsinput,mpsformat,mpsversion) -- somehow return ... fails here
---~ if lfs.isfile(mpsformat) then
---~ commands.writestatus("mplib","loading '%s' from '%s'", mpsinput, mpsformat)
---~ return metapost.load(mpsformat)
---~ else
---~ commands.writestatus("mplib","problems with '%s' from '%s'", mpsinput, mpsformat)
---~ end
---~ end
-
-function metapost.checkformat(mpsinput)
- local mpsversion = environment.version or "unset version"
- local mpsinput = file.addsuffix(mpsinput or "metafun", "mp")
- local mpsformat = file.removesuffix(file.basename(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 mpsformatfullname = caches.getfirstreadablefile(mpsformat,"formats") or ""
- if mpsformatfullname ~= "" then
- commands.writestatus("mplib","loading '%s' from '%s'", mpsinput, mpsformatfullname)
- local mpx, result = metapost.load(mpsformatfullname)
+if mplibone then
+
+ local preamble = [[
+ boolean mplib ; mplib := true ;
+ string mp_parent_version ; mp_parent_version := "%s" ;
+ input %s ; dump ;
+ ]]
+
+ metapost.parameters = {
+ hash_size = 100000,
+ main_memory = 4000000,
+ max_in_open = 50,
+ param_size = 100000,
+ }
+
+ function metapost.make(name, target, version)
+ 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.removesuffix(target),
+ }
+ ) )
if mpx then
- local result = mpx:execute("show mp_parent_version ;")
- if not result.log then
- metapost.reporterror(result)
- else
- local version = match(result.log,">> *(.-)[\n\r]") or "unknown"
- version = gsub(version,"[\'\"]","")
- if version ~= mpsversion then
- commands.writestatus("mplib","version mismatch: %s <> %s", version or "unknown", mpsversion)
+ starttiming(metapost.exectime)
+ local result = mpx:execute(format(preamble,version or "unknown",name))
+ stoptiming(metapost.exectime)
+ mpx:finish()
+ end
+ stoptiming(mplib)
+ end
+
+ function metapost.load(name)
+ starttiming(mplib)
+ local mpx = mplib.new ( table.merged (
+ metapost.parameters,
+ {
+ ini_version = false,
+ mem_name = file.replacesuffix(name,"mem"),
+ find_file = finder,
+ -- job_name = "mplib",
+ }
+ ) )
+ local result
+ if not mpx then
+ result = { status = 99, error = "out of memory"}
+ end
+ stoptiming(mplib)
+ return mpx, result
+ end
+
+ function metapost.checkformat(mpsinput)
+ local mpsversion = environment.version or "unset version"
+ local mpsinput = file.addsuffix(mpsinput or "metafun", "mp")
+ local mpsformat = file.removesuffix(file.basename(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 mpsformatfullname = caches.getfirstreadablefile(mpsformat,"formats") or ""
+ if mpsformatfullname ~= "" then
+ commands.writestatus("mplib","loading '%s' from '%s'", mpsinput, mpsformatfullname)
+ local mpx, result = metapost.load(mpsformatfullname)
+ if mpx then
+ local result = mpx:execute("show mp_parent_version ;")
+ if not result.log then
+ metapost.reporterror(result)
else
- return mpx
+ local version = match(result.log,">> *(.-)[\n\r]") or "unknown"
+ version = gsub(version,"[\'\"]","")
+ if version ~= mpsversion then
+ commands.writestatus("mplib","version mismatch: %s <> %s", version or "unknown", mpsversion)
+ else
+ return mpx
+ end
end
+ else
+ commands.writestatus("mplib","error in loading '%s' from '%s'", mpsinput, mpsformatfullname)
+ metapost.reporterror(result)
end
+ end
+ local mpsformatfullname = caches.setfirstwritablefile(mpsformat,"formats")
+ commands.writestatus("mplib","making '%s' into '%s'", mpsinput, mpsformatfullname)
+ metapost.make(mpsinput,mpsformatfullname,mpsversion) -- somehow return ... fails here
+ if lfs.isfile(mpsformatfullname) then
+ commands.writestatus("mplib","loading '%s' from '%s'", mpsinput, mpsformatfullname)
+ return metapost.load(mpsformatfullname)
+ else
+ commands.writestatus("mplib","problems with '%s' from '%s'", mpsinput, mpsformatfullname)
+ end
+ end
+
+else
+
+ local preamble = [[
+ boolean mplib ; mplib := true ;
+ let dump = endinput ;
+ input %s ;
+ ]]
+
+ function metapost.load(name)
+ starttiming(mplib)
+ local mpx = mplib.new {
+ ini_version = true,
+ find_file = finder,
+ }
+ local result
+ if not mpx then
+ result = { status = 99, error = "out of memory"}
+ else
+ result = mpx:execute(format(preamble, file.replacesuffix(name,"mp")))
+ end
+ stoptiming(mplib)
+ metapost.reporterror(result)
+ return mpx, result
+ end
+
+ function metapost.checkformat(mpsinput)
+ local mpsversion = environment.version or "unset version"
+ local mpsinput = file.addsuffix(mpsinput or "metafun", "mp")
+ commands.writestatus("mplib","loading '%s' (experimental metapost version two)",mpsinput)
+ local mpx, result = metapost.load(mpsinput)
+ if mpx then
+ return mpx
else
- commands.writestatus("mplib","error in loading '%s' from '%s'", mpsinput, mpsformatfullname)
+ commands.writestatus("mplib","error in loading '%s'",mpsinput)
metapost.reporterror(result)
end
end
- local mpsformatfullname = caches.setfirstwritablefile(mpsformat,"formats")
- commands.writestatus("mplib","making '%s' into '%s'", mpsinput, mpsformatfullname)
- metapost.make(mpsinput,mpsformatfullname,mpsversion) -- somehow return ... fails here
- if lfs.isfile(mpsformatfullname) then
- commands.writestatus("mplib","loading '%s' from '%s'", mpsinput, mpsformatfullname)
- return metapost.load(mpsformatfullname)
- else
- commands.writestatus("mplib","problems with '%s' from '%s'", mpsinput, mpsformatfullname)
+
+end
+
+function metapost.unload(mpx)
+ starttiming(mplib)
+ if mpx then
+ mpx:finish()
end
+ stoptiming(mplib)
end
local mpxformats = { }
diff --git a/tex/context/base/mult-de.tex b/tex/context/base/mult-de.tex
index f6f4f3bf9..608fdb1f8 100644
--- a/tex/context/base/mult-de.tex
+++ b/tex/context/base/mult-de.tex
@@ -90,6 +90,7 @@
\setinterfacevariable{bib}{bib}
\setinterfacevariable{big}{gross}
\setinterfacevariable{bigbodyfont}{bigbodyfont}
+\setinterfacevariable{bigger}{bigger}
\setinterfacevariable{bigpreference}{grosszuegig}
\setinterfacevariable{blank}{blanko}
\setinterfacevariable{blockquote}{blockquote}
@@ -364,6 +365,7 @@
\setinterfacevariable{random}{zufaellig}
\setinterfacevariable{readonly}{nurlesbar}
\setinterfacevariable{rectangular}{rechteckig}
+\setinterfacevariable{reference}{referenz}
\setinterfacevariable{referral}{merkmal}
\setinterfacevariable{register}{register}
\setinterfacevariable{regular}{regular}
@@ -411,6 +413,7 @@
\setinterfacevariable{smallbolditalic}{kleinfettitalic}
\setinterfacevariable{smallboldslanted}{kleinfettgeneigt}
\setinterfacevariable{smallcaps}{smallcaps}
+\setinterfacevariable{smaller}{smaller}
\setinterfacevariable{smallitalic}{kleinitalic}
\setinterfacevariable{smallitalicbold}{kleinitalicfett}
\setinterfacevariable{smallnormal}{kleinnormal}
diff --git a/tex/context/base/mult-def.lua b/tex/context/base/mult-def.lua
index ce5af2bba..d877ad0f2 100644
--- a/tex/context/base/mult-def.lua
+++ b/tex/context/base/mult-def.lua
@@ -11143,6 +11143,14 @@ return {
["en"]="up",
["nl"]="omhoog",
},
+ ["smaller"]={
+ ["en"]="smaller",
+ ["nl"]="kleiner",
+ },
+ ["bigger"]={
+ ["en"]="bigger",
+ ["nl"]="groter",
+ },
["underbar"]={
["cs"]="podtrzeno",
["de"]="unterstrichen",
@@ -14721,6 +14729,16 @@ return {
["pe"]="مراجعه",
["ro"]="referinta",
},
+ ["reference"]={
+ ["cs"]="odkaz",
+ ["de"]="referenz",
+ ["en"]="reference",
+ ["fr"]="reference",
+ ["it"]="riferimento",
+ ["nl"]="referentie",
+ ["pe"]="مرجع",
+ ["ro"]="referinta",
+ },
["register"]={
["cs"]="rejstrik",
["de"]="register",
diff --git a/tex/context/base/mult-en.tex b/tex/context/base/mult-en.tex
index 20917a034..cbaeb50d6 100644
--- a/tex/context/base/mult-en.tex
+++ b/tex/context/base/mult-en.tex
@@ -90,6 +90,7 @@
\setinterfacevariable{bib}{bib}
\setinterfacevariable{big}{big}
\setinterfacevariable{bigbodyfont}{bigbodyfont}
+\setinterfacevariable{bigger}{bigger}
\setinterfacevariable{bigpreference}{bigpreference}
\setinterfacevariable{blank}{blank}
\setinterfacevariable{blockquote}{blockquote}
@@ -364,6 +365,7 @@
\setinterfacevariable{random}{random}
\setinterfacevariable{readonly}{readonly}
\setinterfacevariable{rectangular}{rectangular}
+\setinterfacevariable{reference}{reference}
\setinterfacevariable{referral}{referral}
\setinterfacevariable{register}{register}
\setinterfacevariable{regular}{regular}
@@ -411,6 +413,7 @@
\setinterfacevariable{smallbolditalic}{smallbolditalic}
\setinterfacevariable{smallboldslanted}{smallboldslanted}
\setinterfacevariable{smallcaps}{smallcaps}
+\setinterfacevariable{smaller}{smaller}
\setinterfacevariable{smallitalic}{smallitalic}
\setinterfacevariable{smallitalicbold}{smallitalicbold}
\setinterfacevariable{smallnormal}{smallnormal}
diff --git a/tex/context/base/mult-fr.tex b/tex/context/base/mult-fr.tex
index 5244565e9..05b4ed1db 100644
--- a/tex/context/base/mult-fr.tex
+++ b/tex/context/base/mult-fr.tex
@@ -90,6 +90,7 @@
\setinterfacevariable{bib}{bib}
\setinterfacevariable{big}{grand}
\setinterfacevariable{bigbodyfont}{grandepolicecorp}
+\setinterfacevariable{bigger}{bigger}
\setinterfacevariable{bigpreference}{grandepreference}
\setinterfacevariable{blank}{vide}
\setinterfacevariable{blockquote}{blockquote}
@@ -364,6 +365,7 @@
\setinterfacevariable{random}{aleatoire}
\setinterfacevariable{readonly}{lectureseule}
\setinterfacevariable{rectangular}{rectangulaire}
+\setinterfacevariable{reference}{reference}
\setinterfacevariable{referral}{referral}
\setinterfacevariable{register}{registre}
\setinterfacevariable{regular}{regulier}
@@ -411,6 +413,7 @@
\setinterfacevariable{smallbolditalic}{italiquegraspetit}
\setinterfacevariable{smallboldslanted}{inclinegraspetit}
\setinterfacevariable{smallcaps}{petitescapitales}
+\setinterfacevariable{smaller}{smaller}
\setinterfacevariable{smallitalic}{italiquepetit}
\setinterfacevariable{smallitalicbold}{grasitaliquepetit}
\setinterfacevariable{smallnormal}{normalpetit}
diff --git a/tex/context/base/mult-it.tex b/tex/context/base/mult-it.tex
index ce14800de..5bac8d0b0 100644
--- a/tex/context/base/mult-it.tex
+++ b/tex/context/base/mult-it.tex
@@ -90,6 +90,7 @@
\setinterfacevariable{bib}{bib}
\setinterfacevariable{big}{grande}
\setinterfacevariable{bigbodyfont}{grossofontdeltesto}
+\setinterfacevariable{bigger}{bigger}
\setinterfacevariable{bigpreference}{grandepreferenza}
\setinterfacevariable{blank}{rigovuoto}
\setinterfacevariable{blockquote}{blockquote}
@@ -364,6 +365,7 @@
\setinterfacevariable{random}{casuale}
\setinterfacevariable{readonly}{solalettura}
\setinterfacevariable{rectangular}{rettangolare}
+\setinterfacevariable{reference}{riferimento}
\setinterfacevariable{referral}{referral}
\setinterfacevariable{register}{registro}
\setinterfacevariable{regular}{regolare}
@@ -411,6 +413,7 @@
\setinterfacevariable{smallbolditalic}{piccolograssettocorsivo}
\setinterfacevariable{smallboldslanted}{piccolograssettoinclinato}
\setinterfacevariable{smallcaps}{maiuscoletto}
+\setinterfacevariable{smaller}{smaller}
\setinterfacevariable{smallitalic}{piccolocorsivo}
\setinterfacevariable{smallitalicbold}{piccolocorsivograssetto}
\setinterfacevariable{smallnormal}{piccolonormale}
diff --git a/tex/context/base/mult-nl.tex b/tex/context/base/mult-nl.tex
index 074d5f3d5..58c106a22 100644
--- a/tex/context/base/mult-nl.tex
+++ b/tex/context/base/mult-nl.tex
@@ -90,6 +90,7 @@
\setinterfacevariable{bib}{bib}
\setinterfacevariable{big}{groot}
\setinterfacevariable{bigbodyfont}{grootkorps}
+\setinterfacevariable{bigger}{groter}
\setinterfacevariable{bigpreference}{grotevoorkeur}
\setinterfacevariable{blank}{blanko}
\setinterfacevariable{blockquote}{blokcitaat}
@@ -364,6 +365,7 @@
\setinterfacevariable{random}{willekeurig}
\setinterfacevariable{readonly}{alleenleesbaar}
\setinterfacevariable{rectangular}{recht}
+\setinterfacevariable{reference}{referentie}
\setinterfacevariable{referral}{kenmerk}
\setinterfacevariable{register}{register}
\setinterfacevariable{regular}{regular}
@@ -411,6 +413,7 @@
\setinterfacevariable{smallbolditalic}{kleinvetitalic}
\setinterfacevariable{smallboldslanted}{kleinvetschuin}
\setinterfacevariable{smallcaps}{smallcaps}
+\setinterfacevariable{smaller}{kleiner}
\setinterfacevariable{smallitalic}{kleinitalic}
\setinterfacevariable{smallitalicbold}{kleinitalicvet}
\setinterfacevariable{smallnormal}{kleinnormaal}
diff --git a/tex/context/base/mult-ro.tex b/tex/context/base/mult-ro.tex
index 738e49f72..48993ae1f 100644
--- a/tex/context/base/mult-ro.tex
+++ b/tex/context/base/mult-ro.tex
@@ -90,6 +90,7 @@
\setinterfacevariable{bib}{bib}
\setinterfacevariable{big}{mare}
\setinterfacevariable{bigbodyfont}{bigbodyfont}
+\setinterfacevariable{bigger}{bigger}
\setinterfacevariable{bigpreference}{preferintamare}
\setinterfacevariable{blank}{blank}
\setinterfacevariable{blockquote}{blockquote}
@@ -364,6 +365,7 @@
\setinterfacevariable{random}{aleator}
\setinterfacevariable{readonly}{readonly}
\setinterfacevariable{rectangular}{rectangular}
+\setinterfacevariable{reference}{referinta}
\setinterfacevariable{referral}{referinta}
\setinterfacevariable{register}{registru}
\setinterfacevariable{regular}{regular}
@@ -411,6 +413,7 @@
\setinterfacevariable{smallbolditalic}{micaldininclinat}
\setinterfacevariable{smallboldslanted}{micaldininclinat}
\setinterfacevariable{smallcaps}{majusculemici}
+\setinterfacevariable{smaller}{smaller}
\setinterfacevariable{smallitalic}{micitalic}
\setinterfacevariable{smallitalicbold}{micitalicaldin}
\setinterfacevariable{smallnormal}{micnormal}
diff --git a/tex/context/base/mult-sys.tex b/tex/context/base/mult-sys.tex
index 8804c470b..8b00b8d73 100644
--- a/tex/context/base/mult-sys.tex
+++ b/tex/context/base/mult-sys.tex
@@ -233,6 +233,7 @@
\definesystemconstant {handling}
\definesystemconstant {features}
\definesystemconstant {fallbacks}
+\definesystemconstant {goodies}
\definesystemconstant {background}
\definesystemconstant {ucmap}
@@ -491,6 +492,7 @@
\definesystemvariable {ds} % DoorSpringen
\definesystemvariable {ef} % ExternFiguur
\definesystemvariable {ec} % EnCoding
+\definesystemvariable {el} % Elements
\definesystemvariable {en} % ENvironments
\definesystemvariable {ep} % ExternfiguurPreset
\definesystemvariable {eq} % EQalign
@@ -564,6 +566,7 @@
\definesystemvariable {ma} % MargeAchtergrond
\definesystemvariable {mb} % MargeBlokken
\definesystemvariable {md} % MoDule
+\definesystemvariable {me} % MultilingualElement (tags)
\definesystemvariable {mg} % Metapost paGe
\definesystemvariable {mh} % MultilingualHead
\definesystemvariable {mk} % MarKering
diff --git a/tex/context/base/node-acc.lua b/tex/context/base/node-acc.lua
new file mode 100644
index 000000000..f5c33a793
--- /dev/null
+++ b/tex/context/base/node-acc.lua
@@ -0,0 +1,102 @@
+if not modules then modules = { } end modules ['node-acc'] = {
+ version = 1.001,
+ comment = "companion to node-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local traverse_nodes, traverse_id, has_attribute, copy_node = node.traverse, node.traverse_id, node.has_attribute, node.copy
+
+nodes.accessibility = nodes.accessibility or { }
+
+local glue = node.id("glue")
+local glyph = node.id("glyph")
+local hlist = node.id("hlist")
+local vlist = node.id("vlist")
+
+local function injectspaces(head)
+ local p
+ for n in traverse_nodes(head) do
+ local id = n.id
+ if id == glue then -- todo: check for subtype related to spacing (13/14 but most seems to be 0)
+ -- local at = has_attribute(n,attribute)
+ -- if at then
+ if p and p.id == glyph then
+ local g = copy_node(p)
+ local s = copy_node(n.spec)
+ g.char, n.spec = 32, s
+ p.next, g.prev = g, p
+ g.next, n.prev = n, g
+ s.width = s.width - g.width
+ end
+ -- end
+ elseif id == hlist or id == vlist then
+ injectspaces(n.list,attribute)
+ end
+ p = n
+ end
+ return head, true
+end
+
+nodes.accessibility.handler = injectspaces
+
+-- nodes.accessibility.handler(tex.box[255].list)
+
+-- todo:
+
+--~ local a_hyphenated = attributes.private('hyphenated')
+--~
+--~ local hyphenated, codes = { }, { }
+--~
+--~ local function compact(n)
+--~ local t = { }
+--~ for n in traverse_id(glyph,n) do
+--~ t[#t+1] = utfchar(n.char) -- check for unicode
+--~ end
+--~ return concat(t,"")
+--~ end
+--~
+--~ local function injectspans(head)
+--~ for n in traverse_nodes(head) do
+--~ local id = n.id
+--~ if id == disc then
+--~ local r, p = n.replace, n.pre
+--~ if r and p then
+--~ local str = compact(r)
+--~ local hsh = hyphenated[str]
+--~ if not hsh then
+--~ hsh = #codes + 1
+--~ hyphenated[str] = hsh
+--~ codes[hsh] = str
+--~ end
+--~ set_attribute(n,a_hyphenated,hsh)
+--~ end
+--~ elseif id == hlist or id == vlist then
+--~ injectspans(n.list)
+--~ end
+--~ end
+--~ return head, true
+--~ end
+--~
+--~ nodes.injectspans = injectspans
+--~
+--~ tasks.appendaction("processors", "words", "nodes.injectspans")
+--~
+--~ local function injectspans(head)
+--~ for n in traverse_nodes(head) do
+--~ local id = n.id
+--~ if id == disc then
+--~ local a = has_attribute(n,a_hyphenated)
+--~ if a then
+--~ local str = codes[a]
+--~ local b = new_pdfliteral(format("/Span << /ActualText %s >> BDC", lpdf.tosixteen(str)))
+--~ local e = new_pdfliteral("EMC")
+--~ node.insert_before(head,n,b)
+--~ node.insert_after(head,n,e)
+--~ end
+--~ elseif id == hlist or id == vlist then
+--~ injectspans(n.list)
+--~ end
+--~ end
+--~ end
diff --git a/tex/context/base/node-aux.lua b/tex/context/base/node-aux.lua
index 9ed71fd72..5ddf31e25 100644
--- a/tex/context/base/node-aux.lua
+++ b/tex/context/base/node-aux.lua
@@ -8,9 +8,11 @@ if not modules then modules = { } end modules ['node-aux'] = {
local gsub, format = string.gsub, string.format
-local free_node = node.free
-local hpack_nodes = node.hpack
-local node_fields = node.fields
+local free_node, hpack_nodes, node_fields, traverse_nodes = node.free, node.hpack, node.fields, node.traverse
+local has_attribute, set_attribute, unset_attribute, has_attribute = node.has_attribute, node.set_attribute, node.unset_attribute,node.has_attribute
+
+local hlist = node.id("hlist")
+local vlist = node.id("vlist")
function nodes.repack_hlist(list,...)
local temp, b = hpack_nodes(list,...)
@@ -143,3 +145,42 @@ end
-- end
-- end
+
+local function set_attributes(head,attr,value)
+ for n in traverse_nodes(head) do
+ set_attribute(n,attr,value)
+ local id = n.id
+ if id == hlist or id == vlist then
+ set_attributes(n.list,attr,value)
+ end
+ end
+end
+
+local function set_unset_attributes(head,attr,value)
+ for n in traverse_nodes(head) do
+ if not has_attribute(n,attr) then
+ set_attribute(n,attr,value)
+ end
+ local id = n.id
+ if id == hlist or id == vlist then
+ set_unset_attributes(n.list,attr,value)
+ end
+ end
+end
+
+local function unset_attributes(head,attr)
+ for n in traverse_nodes(head) do
+ unset_attribute(n,attr)
+ local id = n.id
+ if id == hlist or id == vlist then
+ unset_attributes(n.list,attr)
+ end
+ end
+end
+
+nodes.set_attribute = set_attribute
+nodes.unset_attribute = unset_attribute
+nodes.has_attribute = has_attribute
+nodes.set_attributes = set_attributes
+nodes.set_unset_attributes = set_unset_attributes
+nodes.unset_attributes = unset_attributes
diff --git a/tex/context/base/node-ini.mkiv b/tex/context/base/node-ini.mkiv
index 23cf7b842..a5559e85d 100644
--- a/tex/context/base/node-ini.mkiv
+++ b/tex/context/base/node-ini.mkiv
@@ -32,6 +32,7 @@
\registerctxluafile{node-ext}{1.001}
\registerctxluafile{node-inj}{1.001} % we might split it off
\registerctxluafile{node-typ}{1.001} % experimental
+\registerctxluafile{node-acc}{1.001} % experimental
\newcount\shownodescounter
diff --git a/tex/context/base/node-ref.lua b/tex/context/base/node-ref.lua
index e85b50910..a25cf1f4a 100644
--- a/tex/context/base/node-ref.lua
+++ b/tex/context/base/node-ref.lua
@@ -338,7 +338,9 @@ nodes.setreference = setreference
local function makereference(width,height,depth,reference)
local sr = stack[reference]
if sr then
- report_backends("resolving reference attribute %s",reference)
+ if trace_references then
+ report_backends("resolving reference attribute %s",reference)
+ end
local resolved, ht, dp, set = sr[1], sr[2], sr[3], sr[4]
if ht then
if height < ht then height = ht end
@@ -363,10 +365,10 @@ local function makereference(width,height,depth,reference)
result.width, result.height, result.depth = 0, 0, 0
if cleanupreferences then stack[reference] = nil end
return result, resolved
- else
+ elseif trace_references then
report_backends("unable to resolve reference annotation %s",reference)
end
- else
+ elseif trace_references then
report_backends("unable to resolve reference attribute %s",reference)
end
end
@@ -402,7 +404,9 @@ nodes.setdestination = setdestination
local function makedestination(width,height,depth,reference)
local sr = stack[reference]
if sr then
- report_backends("resolving destination attribute %s",reference)
+ if trace_destinations then
+ report_backends("resolving destination attribute %s",reference)
+ end
local resolved, ht, dp, name, view = sr[1], sr[2], sr[3], sr[4], sr[5]
if ht then
if height < ht then height = ht end
@@ -443,7 +447,7 @@ local function makedestination(width,height,depth,reference)
result.width, result.height, result.depth = 0, 0, 0
if cleanupdestinations then stack[reference] = nil end
return result, resolved
- else
+ elseif trace_destinations then
report_backends("unable to resolve destination attribute %s",reference)
end
end
diff --git a/tex/context/base/node-res.lua b/tex/context/base/node-res.lua
index 21bcae1d4..546f56916 100644
--- a/tex/context/base/node-res.lua
+++ b/tex/context/base/node-res.lua
@@ -290,4 +290,4 @@ statistics.register("node memory usage", function() -- comes after cleanup !
return status.node_mem_usage
end)
-lua.registerfinalizer(nodes.cleanup_reserved)
+lua.registerfinalizer(nodes.cleanup_reserved, "cleanup reserved nodes")
diff --git a/tex/context/base/node-rul.lua b/tex/context/base/node-rul.lua
index 74a730893..5e1df2da4 100644
--- a/tex/context/base/node-rul.lua
+++ b/tex/context/base/node-rul.lua
@@ -17,28 +17,33 @@ local rule = node.id("rule")
function nodes.strip_range(first,last) -- todo: dir
if first and last then -- just to be sure
- local current = first
- while current and current ~= last do
- local id = current.id
- if id == glyph or id == disc then
- --~ if id == glyph or id == rule or id == disc then
- first = current
+ if first == last then
+ return first, last
+ end
+ while first and first ~= last do
+ local id = first.id
+ if id == glyph or id == disc then -- or id == rule
break
else
- current = current.next
+ first = first.next
end
end
- local current = last
- while current and current ~= first do
- local id = current.id
- --~ if id == glyph or id == rule or id == disc then
- if id == glyph or id == disc then
- last = current
+ if not first then
+ return nil, nil
+ elseif first == last then
+ return first, last
+ end
+ while last and last ~= first do
+ local id = last.id
+ if id == glyph or id == disc then -- or id == rule
break
else
- current = current.prev
+ last = last.prev
end
end
+ if not last then
+ return nil, nil
+ end
end
return first, last
end
@@ -94,11 +99,13 @@ local checkdir = true
-- this one needs to take layers into account (i.e. we need a list of
-- critical attributes)
+-- omkeren class en level -> scheelt functie call in analyse
+
local function process_words(attribute,data,flush,head,parent) -- we have hlistdir and local dir
local n = head
if n then
- local f, l, a, d, i, level
- local continue, done, strip = false, false, false
+ local f, l, a, d, i, class
+ local continue, done, strip, level = false, false, true, -1
while n do
local id = n.id
if id == glyph or id == rule then
@@ -111,12 +118,18 @@ local function process_words(attribute,data,flush,head,parent) -- we have hlistd
l = n
else
-- possible extensions: when in same class then keep spanning
+ local newlevel, newclass = floor(aa/1000), aa%1000
+--~ strip = not continue or level == 1 -- 0
if f then
- head, done = flush(head,f,l,d,level,parent,strip), true
+ if class == newclass then -- and newlevel > level then
+ head, done = flush(head,f,l,d,level,parent,false), true
+ else
+ head, done = flush(head,f,l,d,level,parent,strip), true
+ end
end
f, l, a = n, n, aa
- level, i = floor(a/1000), a%1000
- d = data[i]
+ level, class = newlevel, newclass
+ d = data[class]
continue = d.continue == variables.yes
end
else
@@ -142,10 +155,18 @@ local function process_words(attribute,data,flush,head,parent) -- we have hlistd
end
elseif f then
if continue then
- if id == penalty or id == kern then
+ if id == penalty then
l = n
- elseif id == glue then
+ elseif id == kern then
l = n
+ elseif id == glue then
+ -- catch \underbar{a} \underbar{a} (subtype test is needed)
+ if continue and has_attribute(n,attribute) and n.subtype == 0 then
+ l = n
+ else
+ head, done = flush(head,f,l,d,level,parent,strip), true
+ f, l, a = nil, nil, nil
+ end
end
else
head, done = flush(head,f,l,d,level,parent,strip), true
@@ -183,13 +204,23 @@ local a_viewerlayer = attributes.private("viewerlayer")
local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but acceptable for this purpose
-- check for f and l
-if f.id ~= glyph then
- -- saveguard ... we need to deal with rules and so (math)
- return head
-end
+ if f.id ~= glyph then
+ -- saveguard ... we need to deal with rules and so (math)
+ return head
+ end
local r, m
- if true then
- f, l = strip_range(f,l)
+ if strip then
+ if trace_ruled then
+ local before = n_tosequence(f,l,true)
+ f, l = strip_range(f,l)
+ local after = n_tosequence(f,l,true)
+ report_ruled("range stripper: %s -> %s",before,after)
+ else
+ f, l = strip_range(f,l)
+ end
+ end
+ if not f then
+ return head
end
local w = list_dimensions(parent.glue_set,parent.glue_sign,parent.glue_order,f,l.next)
local method, offset, continue, dy, rulethickness, unit, order, max, ma, ca, ta =
@@ -214,11 +245,11 @@ end
local dp = -(offset+(i-1)*dy-rulethickness)*e + m
local r = new_rule(w,ht,dp)
local v = has_attribute(f,a_viewerlayer)
--- quick hack
-if v then
- set_attribute(r,a_viewerlayer,v)
-end
---
+ -- quick hack
+ if v then
+ set_attribute(r,a_viewerlayer,v)
+ end
+ --
if color then
set_attribute(r,a_colorspace,colorspace)
set_attribute(r,a_color,color)
diff --git a/tex/context/base/node-rul.mkiv b/tex/context/base/node-rul.mkiv
index 1270eb81d..8e6aa5790 100644
--- a/tex/context/base/node-rul.mkiv
+++ b/tex/context/base/node-rul.mkiv
@@ -122,11 +122,13 @@
\glet\dodoruled\dodoruledindeed
\dodoruled}
-\def\dodoruledindeed#1%
+\def\dodoruledindeed#1% maybe reverse the 1000
{\advance\csname\??on:#1:c\endcsname\plusone
\scratchcounter\csname\??on:#1:c\endcsname
- \attribute\ruledattribute\numexpr1000*\scratchcounter
- +\csname\??on#1\ifcsname\??on#1:\number\scratchcounter\s!parent\endcsname:\number\scratchcounter\fi:a\endcsname}
+ \attribute\ruledattribute\numexpr
+ 1000*\scratchcounter
+ +\csname\??on#1\ifcsname\??on#1:\number\scratchcounter\s!parent\endcsname:\number\scratchcounter\fi:a\endcsname
+ \relax}
% ungrouped
diff --git a/tex/context/base/node-tra.lua b/tex/context/base/node-tra.lua
index 880b21b81..d2d02c8df 100644
--- a/tex/context/base/node-tra.lua
+++ b/tex/context/base/node-tra.lua
@@ -343,7 +343,7 @@ function nodes.tosequence(start,stop,compact)
if start.components then
t[#t+1] = nodes.tosequence(start.components,nil,compact)
else
- t[#t+1] = format("%s",utfchar(c))
+ t[#t+1] = utfchar(c)
end
else
t[#t+1] = format("U+%04X:%s",c,utfchar(c))
diff --git a/tex/context/base/pack-rul.mkiv b/tex/context/base/pack-rul.mkiv
index afacc2901..272ef0544 100644
--- a/tex/context/base/pack-rul.mkiv
+++ b/tex/context/base/pack-rul.mkiv
@@ -2011,10 +2011,10 @@
%D sort of newline signal. In horizontal boxes it expands to a
%D space.
-\def\vboxednewline
+\unexpanded\def\vboxednewline
{\endgraf\ignorespaces}
-\def\hboxednewline
+\unexpanded\def\hboxednewline
{\unskip\normalspace\ignorespaces}
%D We can set each rule on or off. The default setting is
diff --git a/tex/context/base/page-ini.mkiv b/tex/context/base/page-ini.mkiv
index 07d342282..497551f46 100644
--- a/tex/context/base/page-ini.mkiv
+++ b/tex/context/base/page-ini.mkiv
@@ -300,11 +300,14 @@
\expandafter\invokenormaloutputroutine
\fi}
-\mainoutput{\invokeoutputroutine} \output{\inotrtrue\the\mainoutput}
+\mainoutput{\invokeoutputroutine}
%D Some hooks:
-\output{\inotrtrue\the\everybeforeoutput\the\mainoutput\the\everyafteroutput}
+\def\setoutputroutine#1%
+ {\global\output{\inotrtrue\the\everybeforeoutput#1\the\everyafteroutput}}
+
+\setoutputroutine{\the\mainoutput}
\ifx\pagediscards\undefined \let\pagediscards\relax \fi
diff --git a/tex/context/base/page-mul.mkiv b/tex/context/base/page-mul.mkiv
index c64fd0c64..791f328c5 100644
--- a/tex/context/base/page-mul.mkiv
+++ b/tex/context/base/page-mul.mkiv
@@ -443,12 +443,14 @@
\vskip-\struttotal
\fi
\global\savedpagetotal\pagetotal
- \global\singlecolumnout\output
+ \global\singlecolumnout\output % hm
%\global\output{\global\setbox\precolumnbox\vbox{\unvbox\normalpagebox}}%
- \global\output{\global\setbox\precolumnbox\vbox{\dotopinsertions\unvbox\normalpagebox}}%
+ %\global\output{\global\setbox\precolumnbox\vbox{\dotopinsertions\unvbox\normalpagebox}}%
+ \setoutputroutine{\global\setbox\precolumnbox\vbox{\dotopinsertions\unvbox\normalpagebox}}%
\eject % no \holdinginserts=1, can make footnote disappear !
\global\precolumnboxheight\ht\precolumnbox
- \global\output{\continuousmulticolumnsout}%
+ %\global\output{\continuousmulticolumnsout}%
+ \setoutputroutine{\continuousmulticolumnsout}%
\setcolumnfloats
\dohandleallcolumns
{\global\setbox\currenttopcolumnbox\emptybox}%
@@ -493,17 +495,21 @@
\par
\ifbalancecolumns
\ifnum\multicolumnendsyncmethod=\plusone
- \global\output{\continuousmulticolumnsout}%
+ %\global\output{\continuousmulticolumnsout}%
+ \setoutputroutine{\continuousmulticolumnsout}%
\goodbreak
\fi
- \global\output{\balancedmulticolumnsout}%
+ %\global\output{\balancedmulticolumnsout}%
+ \setoutputroutine{\balancedmulticolumnsout}%
\else
\goodbreak
\fi
\eject % the prevdepth is important, try e.g. toclist in
\prevdepth\zeropoint % columns before some noncolumned text text
- \global\output\singlecolumnout
- \global\output{\the\mainoutput}% % % % % todo
+ %\global\output\singlecolumnout
+ \setoutputroutine{\singlecolumnout}%
+ %\global\output{\the\mainoutput}% % % % % todo
+ \setoutputroutine{\the\mainoutput}% % % % % todo
\ifvoid\precolumnbox\else
\unvbox\precolumnbox
\fi
@@ -1160,7 +1166,8 @@
\showmessage\m!columns{10}\empty
\global\setbox\firstcolumnbox\vbox{\unvbox0}%
\fi
- \global\output{\balancingerror}%
+ %\global\output{\balancingerror}%
+ \setoutputroutine{\balancingerror}%
\b@selinebottomtrue % forces depth in separation rule
\flushcolumnedpage\plusone
\multicolumnseject
diff --git a/tex/context/base/s-pre-69.tex b/tex/context/base/s-pre-69.tex
new file mode 100644
index 000000000..d65940520
--- /dev/null
+++ b/tex/context/base/s-pre-69.tex
@@ -0,0 +1,314 @@
+%D \module
+%D [ file=s-pre-69,
+%D version=2010.04.28,
+%D title=\CONTEXT\ Style File,
+%D subtitle=Presentation Environment 69,
+%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.
+
+\setuppapersize[S6][S6]
+\setuppapersize[SM][SM]
+
+\usemodule
+ [abr-01,pre-60]
+
+\setupinteraction
+ [state=start,
+ contrastcolor=white,
+ color=white,
+ click=no]
+
+\setuplayout
+ [location=middle,
+ topspace=60pt,
+ bottomspace=80pt,
+ backspace=80pt,
+ header=0pt,
+ footer=0pt,
+ width=middle,
+ height=middle]
+
+\setupcolors
+ [textcolor=white]
+
+\setupbodyfont[euler]
+
+\definecolor[maincolor] [blue]
+\definecolor[extracolor][green]
+
+% \definecolor[maincolor] [red]
+% \definecolor[extracolor][blue]
+
+\startMPinitializations
+ if unknown MyColor[1] :
+ color MyColor[] ;
+ MyColor[1] := transparent(1,.25,\MPcolor{maincolor}) ;
+ MyColor[2] := transparent(1,.25,\MPcolor{extracolor}) ;
+
+ picture MySoFar ; MySoFar := nullpicture ;
+ path MyLastOne ; MyLastOne := origin -- cycle ;
+ color MyPageColor ; MyPageColor := MyColor[1] ;
+ path MyLeftSteps, MyRightSteps ;
+ boolean MyPageDone ; MyPageDone := false ;
+
+ vardef MySmallShape(expr parent) =
+ path p ; p := boundingbox parent ;
+ p := boundingbox parent ;
+ numeric w, h ; w := bbwidth(p) ; h := bbheight(p) ;
+ urcorner p shifted (-uniformdeviate w/4,0) --
+ lrcorner p shifted (0,uniformdeviate h/4) --
+ llcorner p shifted (uniformdeviate w/4,0) --
+ ulcorner p shifted (0,-uniformdeviate h/4) -- cycle
+ enddef ;
+
+ vardef MyShape(expr parent) =
+ path p ; p := boundingbox parent ;
+ if MyPageDone :
+ MyPageDone := false ;
+ urcorner p shifted (-EmWidth + -uniformdeviate CutSpace/2,0) --
+ lrcorner p shifted (0,EmWidth + uniformdeviate BottomSpace/2) --
+ llcorner p shifted (EmWidth + uniformdeviate BackSpace/2,0) --
+ ulcorner p shifted (0,-EmWidth + -uniformdeviate TopSpace/2) -- cycle
+ else :
+ MyPageDone := true ;
+ urcorner p shifted (0,-EmWidth + -uniformdeviate TopSpace/2) --
+ lrcorner p shifted (-EmWidth + -uniformdeviate CutSpace/2,0) --
+ llcorner p shifted (0,EmWidth + uniformdeviate BottomSpace/2) --
+ ulcorner p shifted (EmWidth + uniformdeviate BackSpace/2,0) -- cycle
+ fi
+ enddef ;
+
+ vardef MyMakeOne =
+ MyLastOne := MyShape(Page) ;
+ enddef ;
+
+ vardef MyAddOne =
+ addto MySoFar also image(fill MyLastOne withcolor MyPageColor ; ) ;
+ enddef ;
+
+ vardef MyDrawOne =
+ fill MyLastOne withcolor black ;
+ fill MyLastOne withcolor MyPageColor ;
+ enddef ;
+
+ vardef MyDrawPage =
+ draw MySoFar ;
+ enddef ;
+
+ vardef MySetSteps =
+ path l, r ; numeric s ; path ll[], rr[] ; path t ;
+ l := point 2 of MyLastOne -- point 3 of MyLastOne ;
+ r := point 0 of MyLastOne -- point 1 of MyLastOne ;
+ t := topboundary Field[Text][Text] rightenlarged TextWidth leftenlarged TextWidth ;
+ s := bbheight(Field[Text][Text])/LineHeight + 2 ;
+ t := t shifted (0,-TopSkip) ;
+ for i=1 upto s :
+ ll[i] := t intersectionpoint l ;
+ rr[i] := t intersectionpoint r ;
+ t := t shifted (0,-LineHeight) ;
+ endfor ;
+ MyLeftSteps := for i=1 upto s : ll[i] -- endfor cycle ;
+ MyRightSteps := for i=1 upto s : rr[i] -- endfor cycle ;
+ enddef ;
+
+ vardef MyDrawText(expr txt) =
+ pair a ; a := (point 1 of MyLastOne) - (point 2 of MyLastOne) ;
+ picture p ; p := txt ;
+ p := p
+ shifted (-EmWidth,EmWidth)
+ shifted ulcorner txt
+ shifted point 1 of MyLastOne ;
+ p := p rotatedaround(lrcorner p, radian * tan(ypart a/xpart a)) ;
+ setbounds p to origin -- cycle ;
+ draw p ;
+ enddef ;
+
+ vardef MyDrawTitle(expr txt) =
+ % pair a ; a := (point 2 of MyLastOne) - (point 3 of MyLastOne) ;
+ pair a ; a := (point 3 of MyLastOne) - (point 4 of MyLastOne) ;
+ picture p ;
+ if bbheight(txt) > bbwidth(txt) :
+ p := txt ysized(0.8*TextHeight) ;
+ else :
+ p := txt xsized(0.8*TextWidth) ;
+ fi ;
+ numeric d ; d := arclength(point 2 of MyLastOne -- point 3 of MyLastOne) - bbheight(p) ;
+ p := p
+ shifted (BackSpace,-d/2)
+ shifted -ulcorner p
+ shifted point 3 of MyLastOne ;
+ % p := p rotatedaround(ulcorner p, - radian * tan(xpart a/ypart a)) ;
+ % p := p rotatedaround(ulcorner p, radian * tan(ypart a/xpart a)) ;
+ setbounds p to origin -- cycle ;
+ draw p ;
+ enddef ;
+
+ vardef MyDrawSteps =
+ s := bbheight(Field[Text][Text])/LineHeight + 2 ;
+ for i=1 upto s :
+ draw ll[i] withpen pencircle scaled 1mm ;
+ draw rr[i] withpen pencircle scaled 1mm ;
+ draw ll[i] -- rr[i] ;
+ endfor ;
+ draw Field[Text][Text] ;
+ enddef ;
+
+ fi ;
+\stopMPinitializations
+
+\startuseMPgraphic{initialization}
+ StartPage ;
+ MySoFar := image(fill Page enlarged 12pt withcolor MyPageColor) ;
+ MyMakeOne ;
+ MySetSteps ;
+ StopPage ;
+\stopuseMPgraphic
+
+\appendtoks
+ \startnointerference
+ \useMPgraphic{initialization}
+ \stopnointerference
+\to \everystarttext
+
+\startuseMPgraphic{page}
+ StartPage ;
+ MyDrawPage ;
+ MyDrawOne ;
+ MySetSteps ;
+ MyDrawTitle(textext("\getvariable{document}{title}")) ;
+ MyDrawText(textext("\getvariable{document}{topic}")) ;
+ %
+ % we have multiple runs when we have text
+ %
+% MyDrawSteps ;
+% MyMakeOne ;
+% MySetSteps ;
+ StopPage ;
+\stopuseMPgraphic
+
+\appendtoks
+ \startnointerference
+ \startMPcode
+ MyAddOne ;
+ MyMakeOne ;
+ MySetSteps ;
+ \stopMPcode
+ \stopnointerference
+\to \everyshipout
+
+\defineoverlay[page][\useMPgraphic{page}]
+
+\startuseMPgraphic{symbol}
+ color cc ; cc := MyColor[2] ;
+ path p ; p := MySmallShape(unitsquare scaled (.6*LineHeight)) ;
+ fill p withcolor white ;
+ fill p withcolor cc ;
+\stopuseMPgraphic
+
+\definesymbol[mysymbol][\struttedbox{\useMPgraphic{symbol}}]
+
+\setupitemgroup[itemize][1][symbol=mysymbol]
+
+\setupbackgrounds
+ [page]
+ [background=page]
+
+\startluacode
+ local texdimen = tex.dimen
+ function document.SetParShape()
+ local leftpath = metapost.getclippath("metafun","metafun","clip currentpicture to MyLeftSteps ;")
+ local rightpath = metapost.getclippath("metafun","metafun","clip currentpicture to MyRightSteps ;")
+ local shape = { }
+ for i=1,#leftpath do
+ local left = leftpath[i].x_coord
+ local right = rightpath[i].x_coord
+ local hsize = right - left - (texdimen.backspace + texdimen.cutspace)*number.dimenfactors.bp
+ shape[#shape+1] = string.format("%sbp %sbp",left,hsize)
+ end
+ -- print(table.serialize(shape))
+ tex.sprint(tex.ctxcatcodes,string.format("\\parshape %s %s",#shape,table.concat(shape," ")))
+ end
+\stopluacode
+
+\nopenalties \dontcomplain
+
+\setupwhitespace[none]
+
+\def\StartText#1#2%
+ {\starttext
+ \setvariable{document}{title}{\framed[frame=off,offset=0pt,align=flushleft,foregroundstyle=\tfd\setupinterlinespace]{\begstrut#1\endstrut}}
+ \setvariable{document}{topic}{\tfb#2}
+ \startstandardmakeup
+ % dummy page
+ \stopstandardmakeup
+ \setvariable{document}{title}{}
+ \setvariable{document}{topic}{}}
+
+\def\StopText
+ {\stoptext}
+
+\def\StartItems#1%
+ {\setvariable{document}{topic}{\tfb#1}
+ \startstandardmakeup[top=,bottom=\vss]
+ \ctxlua{document.SetParShape()}
+ \StartSteps}
+
+\def\StopItems
+ {\StopSteps
+ \stopstandardmakeup}
+
+\def\StartItem
+ {\dontleavehmode\llap{\symbol[mysymbol]\quad}\ignorespaces}
+
+\def\StopItem
+ {\removeunwantedspaces\nobreak\crlf\crlf\FlushStep}
+
+\def\ShapeParagraph
+ {\ctxlua{document.SetParShape()}}
+
+% no parshape yet
+
+\def\StartParagraphs#1%
+ {\setvariable{document}{topic}{\tfb#1}
+ \startstandardmakeup[top=,bottom=\vss]
+ %\ctxlua{document.SetParShape()}
+ \StartSteps}
+
+\def\StopParagraphs
+ {\StopSteps
+ \stopstandardmakeup}
+
+\def\StartParagraph
+ {}
+
+\def\StopParagraph
+ {\par\FlushStep}
+
+\doifnotmode{demo}{\endinput}
+
+% finetuning: \StartText{\TEX\ and Reality\vskip2exClashing Mindsets?\vskip1ex}{Bacho\TEX, May 1, 2010}
+
+\StartText{Just\\A Demo}{Bacho\TEX, May 1, 2010}
+
+\StartItems{Quote from Tufte and Ward}
+ \StartItem
+ \input tufte
+ \StopItem
+ \StartItem
+ \input ward
+ \StopItem
+\StopItems
+
+% \dorecurse{20}{
+% \ctxlua{document.SetParShape()}
+% \input tufte
+% \page
+% }
+
+\StopText
+
diff --git a/tex/context/base/strc-bkm.lua b/tex/context/base/strc-bkm.lua
index f34d83ec5..79ed867de 100644
--- a/tex/context/base/strc-bkm.lua
+++ b/tex/context/base/strc-bkm.lua
@@ -9,6 +9,8 @@ if not modules then modules = { } end modules ['strc-bkm'] = {
-- Future version will support adding arbitrary bookmarks with
-- associated complex actions (rather trivial to implement).
+-- this should become proper separated backend code
+
local format, concat, gsub = string.format, table.concat, string.gsub
local texsprint, utfvalues = tex.sprint, string.utfvalues
@@ -100,7 +102,7 @@ function bookmarks.place()
end
end
-lpdf.registerdocumentfinalizer(function() structure.bookmarks.place() end,1)
+lpdf.registerdocumentfinalizer(function() structure.bookmarks.place() end,1,"bookmarks")
-- bkm
--~ function nodes.toutf(list)
diff --git a/tex/context/base/strc-des.mkiv b/tex/context/base/strc-des.mkiv
index 29e4ea36c..42ea701f0 100644
--- a/tex/context/base/strc-des.mkiv
+++ b/tex/context/base/strc-des.mkiv
@@ -375,6 +375,8 @@
\def\@@stopdescription
{\@@placedescriptionclosesymbol
\par % else we loose
+\dostoptagged
+\dostoptagged
\endgroup
\descriptionparameter\c!after % which currentdescription is taken here?
\egroup % temporary hack
@@ -420,15 +422,19 @@
\ifcsname @@description\currentdescriptionlocation\endcsname \else
\let\currentdescriptionlocation\v!left
\fi
+\dostarttagged\t!description\currentdescription
+\dostarttagged\t!descriptiontag\empty
\@@dostartdescription
- \csname @@description\currentdescriptionlocation\endcsname} % args not needed
+ \csname @@description\currentdescriptionlocation\endcsname
+\dostoptagged
+\dostarttagged\t!descriptioncontent\empty} % args not needed
\def\@@makedescription[#1]#2%
- {\postponenotes % new, assumes grouping
- \edef\currentdescriptionreference{#1}%
- \doenumerationcheckconditions
- \dodescriptioncomponent[\c!reference=#1,\c!label={\descriptionparameter\c!text},\c!title={#2},\c!bookmark=,\c!list=][]%
- \@@dostartdescriptionindeed}
+ {\postponenotes % new, assumes grouping
+ \edef\currentdescriptionreference{#1}%
+ \doenumerationcheckconditions
+ \dodescriptioncomponent[\c!reference=#1,\c!label={\descriptionparameter\c!text},\c!title={#2},\c!bookmark=,\c!list=][]%
+ \@@dostartdescriptionindeed}
\def\dostartstoreddescription
{\@@dostartdescriptionindeed}
diff --git a/tex/context/base/strc-flt.mkiv b/tex/context/base/strc-flt.mkiv
index ea52aa82d..1d5114390 100644
--- a/tex/context/base/strc-flt.mkiv
+++ b/tex/context/base/strc-flt.mkiv
@@ -313,14 +313,18 @@
\def\thecurrentfloatnumber
{\ifnofloatcaption \else \ifnofloatnumber \else
\ifx\currentfloatnumber\relax\else
+ \dostarttagged\t!floattag\empty
\labeltexts\currentfloat{\ctxlua{structure.lists.savedprefixednumber("\currentfloat",\currentfloatnumber)}}%
+ \dostoptagged
\fi
\fi \fi}
\def\thecurrentfloatcaption
{\ifnofloatcaption \else
\ifx\currentfloatnumber\relax\else
+ \dostarttagged\t!floattext\empty
\ctxlua{structure.lists.savedtitle("\currentfloat",\currentfloatnumber)}%
+ \dostoptagged
\fi
\fi}
@@ -368,11 +372,11 @@
\begingroup
\dosetfloatcaptionattributes\c!style\c!color
\begingroup
- \dosetfloatcaptionattributes\c!headstyle\c!headcolor
+ \dosetfloatcaptionattributes\c!headstyle\c!headcolor
\labeltexts{#1}{\preparednumber}%
\endgroup
\begingroup
- \dosetfloatcaptionattributes\c!textstyle\c!textcolor
+ \dosetfloatcaptionattributes\c!textstyle\c!textcolor
\dotfskip{\floatcaptionparameter\c!distance}#3%
\endgroup
\endgroup}%
@@ -611,6 +615,7 @@
\fi
\global\insidefloattrue
\begingroup % **
+ \dostarttagged\t!float\currentfloat
\ifmarginblocks
\doifinset\v!margin{#2}{\hsize\@@mbwidth}%
\fi
@@ -620,15 +625,17 @@
\dowithnextboxcontent % better a \the\everyfloattoks
{\setlocalfloathsize
\floatparameter\c!inner
+ \dostarttagged\t!floatcontent\empty
+ \aftergroup\dostoptagged % tricky, never change \dowithnextboxcontent
\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}%
+ \xdocompletefloat{#1}{#3}{#2}{#4}% ** not yet done
+ % we need to carry over the par because of side floats
+ \doifnotinset\v!text{#2}{\dostoptagged\carryoverpar\endgroup}% **
\global\sidefloatdownshift \zeropoint
\global\sidefloatextrashift\zeropoint
\ifparfloat
@@ -799,6 +806,7 @@
\egroup
% place the float
\dofloat{#3}{\thecurrentfloatnumber}{\thecurrentfloatcaption}%
+% \dostoptagged % tricky here, we need an extra mechanism (add to previous or so)
\global\insidefloatfalse}
\def\setlocalfloathsize
@@ -1129,8 +1137,10 @@
\doifnotinset\v!tall{#1}%
{\dp\floatbox\openstrutdepth}% dp\strutbox}% % toegevoegd
\box\floatbox
+ \dostoptagged
\blank[\floatsharedparameter\c!spaceafter]%
\endgroup % **
+% \dostoptagged
\doinsertfloatinfo}
\def\somefacefloat[#1]% links, rechts, midden, hoog, midden, laag
@@ -1271,7 +1281,8 @@
\locatefloat{\copy\tempfloatbox}}}
\def\dopreparedocaption#1#2#3%
- {\doifinsetelse{\floatcaptionparameter\c!location}{\v!top,\v!bottom}
+ {\dostarttagged\t!floatcaption\empty
+ \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
@@ -1287,7 +1298,8 @@
{\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}}}}
+ {\dopreparesidewidthcaption{#1}{#2}{#3}}}%
+ \dostoptagged}
% \def\dosettempcaptionbox
% {\dosetraggedvbox{\floatcaptionparameter\c!align}%
diff --git a/tex/context/base/strc-itm.mkiv b/tex/context/base/strc-itm.mkiv
index ab2f09f40..e012ce447 100644
--- a/tex/context/base/strc-itm.mkiv
+++ b/tex/context/base/strc-itm.mkiv
@@ -310,10 +310,12 @@
% \empty
\else
\getitemparameter\currentitemlevel\c!before
- \fi\fi}
+ \fi\fi
+ \dostarttagged\t!itemgroup\currentitemgroup}
\def\itemaftercommand
- {\ifconditional\nowhitelistitem
+ {\dostoptagged
+ \ifconditional\nowhitelistitem
\ifconditional\afterlistitem
\ifcase\currentitemlevel\or\getitemparameter\currentitemlevel\c!after\fi
\else
@@ -769,7 +771,12 @@
\par
\fi
\dolistreference
- \ifconditional\firstlistitem \else \endgroup \fi % toegevoegd, eerste \som opent groep
+ \ifconditional\firstlistitem
+ \else
+\dostoptagged
+\dostoptagged
+ \endgroup
+ \fi % toegevoegd, eerste \som opent groep
\ifnum\itemcolumndepth=\currentitemlevel\relax
\stopcolumns
\global\itemcolumndepth\zerocount
@@ -1142,6 +1149,9 @@
\chardef\autoitemgroupspacing=2 % 0 = voor/na, 1=tussen als geen voor 2=(prev)tussen=old/normal
+% todo: assume startitem ... stopitem and do an autostopitem .. cleaner for
+% elements
+
\def\complexdoitemgroupitem[#1]%
{\def\currentitemreference{#1}%
\ifconditional\textlistitem
@@ -1176,6 +1186,8 @@
\fi
\fi
\else
+\dostoptagged
+\dostoptagged
\ifconditional\textlistitem % was bugged: \inlinelistitem
\ifhmode
% WS: make the distance between items customizable, think about better default values -> see itemize-1.tex
@@ -1190,7 +1202,10 @@
\vskip-\dimexpr\lastskip+\lineheight\relax
\nobreak
\fi
+\dostarttagged\t!item\empty
+\dostarttagged\t!itemtag\empty
\dolistitem
+\dostoptagged
\relax
\ifconditional\packlistitem
\setupwhitespace[\v!none]%
@@ -1198,6 +1213,7 @@
\getitemparameter\currentitemlevel\c!inner
\marsymbol
\let\marsymbol\relax
+\dostarttagged\t!itemcontent\empty
\strut % added 11-08-99
\setfalse\concatnextitem % new, concat
\nobreak % else problems with intext items
diff --git a/tex/context/base/strc-lst.lua b/tex/context/base/strc-lst.lua
index ea87715c9..6af062134 100644
--- a/tex/context/base/strc-lst.lua
+++ b/tex/context/base/strc-lst.lua
@@ -124,6 +124,26 @@ function lists.enhance(n)
end
end
+function lists.enforce(n)
+ -- todo: symbolic names for counters
+ local l = cached[n]
+ if l then
+ --
+ l.directives = nil -- might change
+ -- save in the right order (happens at shipout)
+ lists.tobesaved[#lists.tobesaved+1] = l
+ -- default enhancer (cross referencing)
+ l.references.realpage = texcount.realpageno
+ -- specific enhancer (kind of obsolete)
+ local kind = l.metadata.kind
+ local enhancer = kind and lists.enhancers[kind]
+ if enhancer then
+ enhancer(l)
+ end
+ return l
+ end
+end
+
-- we can use level instead but we can also decide to remove level from the metadata
local nesting = { }
diff --git a/tex/context/base/strc-lst.mkiv b/tex/context/base/strc-lst.mkiv
index bcf20c451..83faf75a7 100644
--- a/tex/context/base/strc-lst.mkiv
+++ b/tex/context/base/strc-lst.mkiv
@@ -97,6 +97,8 @@
%begingroup\attribute\destinationattribute\currentdestinationattribute\dontleavehmode\hbox{}\endgroup % todo
\dontleavehmode\hbox attr \destinationattribute \currentdestinationattribute{}% todo
% end of new
+ \else
+ \ctxlua{structure.lists.enhance(\currentlistnumber)}% direct injection
\fi
\endgroup}
@@ -104,7 +106,8 @@
{\ctxlua{structure.lists.location(\currentlistindex)}}
\def\structurelistpagenumber
- {\ctxlua{structure.lists.prefixedpage(
+ {\dostarttagged\t!listpage\empty
+ \ctxlua{structure.lists.prefixedpage(
"\currentlist",
\currentlistindex,
{
@@ -120,25 +123,34 @@
starter = \!!bs\listparameter\c!pagestarter\!!es,
stopper = \!!bs\listparameter\c!pagestopper\!!es,
}
- )}}
+ )}%
+ \dostoptagged}
\def\structurelistrealpagenumber
{\ctxlua{structure.lists.realpage("\currentlist",\currentlistindex)}}
\def\structurelistfirst
- {\ctxlua{structure.lists.userdata("\currentlist",\currentlistindex,"first")}}
+ {\dostarttagged\t!listdata{first} % ot always ok
+ \ctxlua{structure.lists.userdata("\currentlist",\currentlistindex,"first")}%
+ \dostoptagged}
\def\structurelistsecond
- {\ctxlua{structure.lists.userdata("\currentlist",\currentlistindex,"second")}}
+ {\dostarttagged\t!listdata{second}%
+ \ctxlua{structure.lists.userdata("\currentlist",\currentlistindex,"second")}%
+ \dostoptagged}
\def\structurelistuservariable#1%
- {\ctxlua{structure.lists.userdata("\currentlist",\currentlistindex,"#1")}}
+ {\dostarttagged\t!listdata{#1}%
+ \ctxlua{structure.lists.userdata("\currentlist",\currentlistindex,"#1")}%
+ \dostoptagged}
% \appendtoks
% \to \everystructurelist
\unexpanded\def\placestructurelist#1#2#3% hm ... [][][]
- {\ctxlua{structure.lists.process("#1","#2","#3")}}
+ {\dostarttagged\t!list\empty
+ \ctxlua{structure.lists.process("#1","#2","#3")}%
+ \dostoptagged}
\unexpanded\def\analysestructurelist#1#2#3%
{\ctxlua{structure.lists.analyze("#1","#2","#3")}}
@@ -173,12 +185,14 @@
\edef\currentlist {#1}%
\edef\currentlistmethod{#2}%
\edef\currentlistindex {#3}%
+ \dostarttagged\t!listitem\currentlist
\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
+ \dostoptagged
\ctxlua{structure.lists.popnesting()}}
% \installstructcurelistprocessor{pubs:userdata}
@@ -902,10 +916,13 @@
\structurelistrealpagenumber}
\def\structurelistgenerictitle
- {\ctxlua{structure.lists.title("\currentlist",\currentlistindex)}}
+ {\dostarttagged\t!listcontent\empty
+ \ctxlua{structure.lists.title("\currentlist",\currentlistindex)}%
+ \dostoptagged}
-\def\structurelistgenericnumber{\ctxlua{
- structure.lists.prefixednumber("\currentlist",\currentlistindex, {
+\def\structurelistgenericnumber
+ {\dostarttagged\t!listtag\empty
+ \ctxlua{structure.lists.prefixednumber("\currentlist",\currentlistindex, {
prefix = "\listparameter\c!prefix",
separatorset = "\listparameter\c!prefixseparatorset",
conversionset = "\listparameter\c!prefixconversionset",
@@ -921,7 +938,8 @@
starter = \!!bs\listparameter\c!numberstarter\!!es,
stopper = \!!bs\listparameter\c!numberstopper\!!es,
segments = "\listparameter\c!numbersegments",
- } )}}
+ } )}%
+ \dostoptagged}
% new and yet undocumented (used in cocoa qa), temporarily disabled in mkiv
%
diff --git a/tex/context/base/strc-mat.mkiv b/tex/context/base/strc-mat.mkiv
index 3728913cb..1e9bd8273 100644
--- a/tex/context/base/strc-mat.mkiv
+++ b/tex/context/base/strc-mat.mkiv
@@ -439,6 +439,7 @@
\def\dodostartformula[#1][#2]% setting leftskip adaption is slow !
{\bgroup % HERE
\def\currentformula{#1}%
+ \dostarttagged\t!formula\currentformula
\the\everybeforedisplayformula
\formulaparskip\parskip
\formulastrutdp\strutdepth
@@ -453,7 +454,7 @@
\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}%
+ \long\def\dostartformula##1{\bgroup\dostarttagged\t!subformula\def\dostopformula{\dostoptagged\egroup}}%
\freezedimenmacro\leftdisplayskip
\freezedimenmacro\rightdisplayskip
\freezedimenmacro\leftdisplaymargin
@@ -474,8 +475,13 @@
\endgroup}
\def\dostopformula
- {\doplaceformulanumber
+ {\dostarttagged\t!formulatag\empty
+ \doplaceformulanumber
+ \dostoptagged
+ \dostarttagged\t!formulacontent\empty
\getvalue{\e!stop\formulaparameter\c!alternative\v!formula}%
+ \dostoptagged
+ \dostoptagged
\nonoindentation
\checknextindentation[\formulaparameter\c!indentnext]%
\egroup
@@ -587,6 +593,7 @@
\def\dostartformulas[#1]#2\stopformulas % new / to be internationalized
{\bgroup
+ \dostarttagged\t!formulaset\empty
\global\settrue\insideformulas
\edef\currentformulasreference{#1}%
\handleformulasnumbering
@@ -611,6 +618,7 @@
\egroup
\stopdisplaymath
\global\setfalse\insideformulas
+ \dostoptagged
\egroup
\the\everyresetformulas
\hangafter\minusone % added for side floats
diff --git a/tex/context/base/strc-not.lua b/tex/context/base/strc-not.lua
index 1e761d657..466bc7a03 100644
--- a/tex/context/base/strc-not.lua
+++ b/tex/context/base/strc-not.lua
@@ -84,7 +84,8 @@ nodes.getn = getn
-- we could make a special enhancer
function notes.listindex(tag,n)
- return notedata[tag][n]
+ local ndt = notedata[tag]
+ return ndt and ndt[n]
end
function notes.define(tag,kind,number)
@@ -98,9 +99,10 @@ function notes.save(tag,newkind)
if trace_notes then
report_notes("saving state of '%s': %s -> %s",tag,state.kind,newkind or state.kind)
end
- state.saved = notedata[tag]
+ state.saveddata = notedata[tag]
state.savedkind = state.kind
state.kind = newkind or state.kind
+ state.saved = true
notedata[tag] = { }
end
end
@@ -111,9 +113,10 @@ function notes.restore(tag,forcedstate)
if trace_notes then
report_notes("restoring state of '%s': %s -> %s",tag,state.kind,state.savedkind)
end
- state.saved = nil
+ notedata[tag] = state.saveddata
state.kind = forcedstate or state.savedkind
- notedata[tag] = state.saved
+ state.saveddata = nil
+ state.saved = false
end
end
@@ -249,13 +252,17 @@ function notes.postpone()
end
end
-function notes.setsymbolpage(tag,n)
- local l = notes.listindex(tag,n)
- local p = texcount.realpageno
- if trace_notes then
- report_notes("note %s of '%s' with list index %s gets page %s",n,tag,l,p)
+function notes.setsymbolpage(tag,n,l)
+ local l = l or notes.listindex(tag,n)
+ if l then
+ local p = texcount.realpageno
+ if trace_notes then
+ report_notes("note %s of '%s' with list index %s gets page %s",n,tag,l,p)
+ end
+ lists.cached[l].references.symbolpage = p
+ else
+ report_notes("internal error: note %s of '%s' is not initialized",n,tag)
end
- lists.cached[l].references.symbolpage = p
end
function notes.getsymbolpage(tag,n)
diff --git a/tex/context/base/strc-not.mkiv b/tex/context/base/strc-not.mkiv
index 751776326..58229a54f 100644
--- a/tex/context/base/strc-not.mkiv
+++ b/tex/context/base/strc-not.mkiv
@@ -637,15 +637,16 @@
\fi}
\def\dolastnotesymbol
- {\typesetsomenotesymbol\currentnote\currentnotenumber}
+ {\typesetsomenotesymbol\currentnote\currentnotenumber\currentdescriptionnumberentry}
-\def\dotypesetsomenotesymbol#1#2% running text
+\def\dotypesetsomenotesymbol#1#2#3% running text (messy: #1 and current mixed)
{\dodonotesymbol
- {\synchronizesomenotesymbol{#1}{#2}%
- \ctxlua{structure.notes.number("\currentnote",\currentnotenumber)}% \currentdescriptionnumberentry
+ {\synchronizesomenotesymbol{#1}{#2}{#3}%
+% \ctxlua{structure.notes.number("\currentnote",\currentnotenumber)}% \currentdescriptionnumberentry
+ \ctxlua{structure.notes.number("#1",#2)}%
\domovednote{#1}{#2}\v!previouspage\v!nextpage}}
-\unexpanded\def\typesetsomenotesymbol#1#2% running text
+\unexpanded\def\typesetsomenotesymbol#1#2#3% running text
{\removeunwantedspaces
\doifitalicelse\/\donothing % Charles IV \footnote{the fourth}
\ifdim\lastkern=\notesignal
@@ -653,8 +654,8 @@
\fi
\nobreak
\doifelse{\noteparameter\c!interaction}\v!no
- {\dotypesetsomenotesymbol{#1}{#2}}
- {\directgotobox{\dotypesetsomenotesymbol{#1}{#2}}[page(\ctxlua{structure.notes.getnumberpage("#1",\number#2)})]}% f:
+ {\dotypesetsomenotesymbol{#1}{#2}{#3}}
+ {\directgotobox{\dotypesetsomenotesymbol{#1}{#2}{#3}}[page(\ctxlua{structure.notes.getnumberpage("#1",\number#2)})]}% f:
\globallet\lastnotesymbol\relax}
\unexpanded\def\typesetdummynotesymbol % temp hack
@@ -698,8 +699,10 @@
\ctxlua{structure.notes.number("\currentnote",\currentdescriptionnumberentry)}%
\domovednote\currentdescription\currentdescriptionnumberentry\v!nextpage\v!previouspage}}
-\def\synchronizesomenotesymbol#1#2% called more often than needed
- {\normalexpanded{\noexpand\ctxlatelua{structure.notes.setsymbolpage("#1",#2)}}}
+\def\synchronizesomenotesymbol#1#2#3% called more often than needed
+ {\iftrialtypesetting\else
+ \normalexpanded{\noexpand\ctxlatelua{structure.notes.setsymbolpage("#1",#2,#3)}}%
+ \fi}
\def\handlenoteinsert#1#2%
{\begingroup
diff --git a/tex/context/base/strc-ref.lua b/tex/context/base/strc-ref.lua
index f9b484173..8fab48697 100644
--- a/tex/context/base/strc-ref.lua
+++ b/tex/context/base/strc-ref.lua
@@ -902,7 +902,7 @@ local function identify(prefix,reference)
set[i] = var
end
jobreferences.currentset = set
--- print(bug,table.serialize(set))
+--~ print(bug,table.serialize(set))
return set, bug
end
diff --git a/tex/context/base/strc-ref.mkiv b/tex/context/base/strc-ref.mkiv
index 921f5927e..91e975ea9 100644
--- a/tex/context/base/strc-ref.mkiv
+++ b/tex/context/base/strc-ref.mkiv
@@ -1081,7 +1081,9 @@
\begingroup
\attribute\referenceattribute\attributeunsetvalue
\iflocation
+\dostarttagged\t!link\empty
\ctxlua{jobreferences.inject("\referenceprefix","#2",\number\ht\strutbox,\number\dp\strutbox,\extrareferencearguments)}%
+\dostoptagged
\setlocationattributes\??ia
\setstrut % can be option
\attribute\referenceattribute\lastreferenceattribute
@@ -1094,7 +1096,9 @@
\begingroup
\attribute\referenceattribute\attributeunsetvalue
\iflocation
+\dostarttagged\t!link\empty
\ctxlua{jobreferences.inject("\referenceprefix","#2",\number\dimexpr\@@iaheight\relax,\number\dimexpr\@@iadepth\relax,\extrareferencearguments)}%
+\dostoptagged
\setlocationattributes\??ia
\attribute\referenceattribute\lastreferenceattribute
\fi
@@ -1109,7 +1113,9 @@
\iflocation
\ctxlua{jobreferences.doifelse("\referenceprefix","#3",\extrareferencearguments)}%
{\expandtexincurrentreference
+\dostarttagged\t!link\empty
\ctxlua{jobreferences.injectcurrentset(\number\ht\strutbox,\number\dp\strutbox)}%
+\dostoptagged
\setlocationattributes\??ia
\setstrut % can be option
\attribute\referenceattribute\lastreferenceattribute}%
@@ -1126,7 +1132,9 @@
\iflocation
\ctxlua{jobreferences.doifelse("\referenceprefix","#3",\extrareferencearguments)}%
{\expandtexincurrentreference
+\dostarttagged\t!link\empty
\ctxlua{jobreferences.injectcurrentset(\number\dimexpr\@@iaheight\relax,\number\dimexpr\@@iadepth\relax)}%
+\dostoptagged
\setlocationattributes\??ia
\attribute\referenceattribute\lastreferenceattribute}%
{\unknownreference{#3}}%
@@ -1139,7 +1147,9 @@
\begingroup
\attribute\referenceattribute\attributeunsetvalue
\iflocation
+\dostarttagged\t!link\empty
\ctxlua{jobreferences.inject("\referenceprefix","#2",nil,nil,\extrareferencearguments)}%
+\dostoptagged
\setlocationattributes\??ia
\hbox attr \referenceattribute \lastreferenceattribute {#1}%
\else
@@ -1152,7 +1162,9 @@
\begingroup
\attribute\referenceattribute\attributeunsetvalue
\iflocation
+\dostarttagged\t!link\empty
\ctxlua{jobreferences.inject("\referenceprefix","#3",nil,nil,\extrareferencearguments)}%
+\dostoptagged
\setlocationcolorspec{#1}% no consequence for strut
\hbox attr \referenceattribute \lastreferenceattribute {#2}%
\else
@@ -1165,7 +1177,9 @@
\begingroup
\attribute\referenceattribute\attributeunsetvalue
\iflocation
+\dostarttagged\t!link\empty
\ctxlua{jobreferences.inject("\referenceprefix","#2",nil,nil,\extrareferencearguments)}%
+\dostoptagged
\hbox attr \referenceattribute \lastreferenceattribute {#1}%
\else
#1%
@@ -1179,7 +1193,9 @@
\iflocation
\ctxlua{jobreferences.doifelse("\referenceprefix","#2",\extrareferencearguments)}%
{\expandtexincurrentreference
+\dostarttagged\t!link\empty
\ctxlua{jobreferences.injectcurrentset(nil,nil)}%
+\dostoptagged
\setlocationattributes\??ia
\hbox attr \referenceattribute \lastreferenceattribute {#1}}%
{\unknownreference{#2}}%
@@ -1187,6 +1203,18 @@
#1%
\fi
\endgroup}
+
+\unexpanded\def\gotowdhtbox#1#2[#3]% fast variant for overlays
+ {\dontleavehmode
+ \begingroup
+ \attribute\referenceattribute\attributeunsetvalue
+ \ctxlua{jobreferences.doifelse("\referenceprefix","#3",\extrareferencearguments)}%
+ {\ctxlua{jobreferences.injectcurrentset(nil,nil)}%
+ \setbox\scratchbox\null\wd\scratchbox#1\ht\scratchbox#2%
+ \hbox attr \referenceattribute \lastreferenceattribute {\box\scratchbox}}%
+ {\unknownreference{#3}}%
+ \endgroup}
+
%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
diff --git a/tex/context/base/strc-reg.mkiv b/tex/context/base/strc-reg.mkiv
index 529e8cd1e..413ccb81a 100644
--- a/tex/context/base/strc-reg.mkiv
+++ b/tex/context/base/strc-reg.mkiv
@@ -577,12 +577,12 @@
\registerparameter\c!command{\strut#1}%
\endgroup
\registerparameter\c!after
- \par\nobreak}
-
+ \par
+ \nobreak}
% b = <goodbreak> <before> <character> <after> <nobreak>
-\setvalue{\??id:\c!indicator:b}#1%
+\setvalue{\??id:\c!indicator:b}#1% will be shared with a
{\registerparameter\c!before
\begingroup\dosetregisterattributes\c!style\c!color
\registerparameter\c!command{\strut#1}%
@@ -603,47 +603,59 @@
\unexpanded\def\startregisteroutput
{\endgraf
\begingroup
+ \dostarttagged\t!register\currentregister
\forgetparindent
\forgetparskip}
\unexpanded\def\stopregisteroutput
{\endgraf
+ \dostoptagged
\endgroup}
\unexpanded\def\startregisterentries#1% depth
{\endgraf
\begingroup
+ \dostarttagged\t!registerentries\empty
\dosetregisterattributes\c!textstyle\c!textcolor
\advance\leftskip\numexpr#1-1\relax\dimexpr\registerparameter\c!distance\relax
\hangindent\registerparameter\c!distance\hangafter\plusone}
\unexpanded\def\stopregisterentries
{\endgraf
+ \dostoptagged
\endgroup}
\unexpanded\def\startregistersection#1% title
- {\registercharacter{#1}\endgraf}
+ {\dostarttagged\t!registersection\empty
+ \dostarttagged\t!registertag\empty
+ \registercharacter{#1}\endgraf
+ \dostoptagged}
\unexpanded\def\stopregistersection
- {\endgraf}
+ {\dostoptagged
+ \endgraf}
\newconditional\registerpagedone
\unexpanded\def\startregisterpages
{\begingroup
+ \dostarttagged\t!registerpages\empty
\setfalse\registerpagedone
\dosetregisterattributes\c!pagestyle\c!pagecolor}
\unexpanded\def\stopregisterpages
- {\endgroup}
+ {\dostoptagged
+ \endgroup}
\unexpanded\def\startregisterseewords
{\begingroup
\setfalse\registerpagedone
+ \dostarttagged\t!registerpage\empty
\dosetregisterattributes\c!pagestyle\c!pagecolor}
\unexpanded\def\stopregisterseewords
- {\endgroup}
+ {\dostoptagged
+ \endgroup}
\def\registerpageseparator% todo: , configurable
{\ifconditional\registerpagedone
@@ -665,20 +677,37 @@
\def\registeronepage#1#2#3% content
{\registerpageseparator
- \withregisterpagecommand{#1}{#2}{#3}}
+ \dostarttagged\t!registerpage\empty
+ \withregisterpagecommand{#1}{#2}{#3}%
+ \dostoptagged}
\def\registerpagerange#1#2#3#4#5#6% content, content todo: -- configurable
{\registerpageseparator
+ \dostarttagged\t!registerpagerange\empty
+ \dostarttagged\t!registerfrompage\empty
\withregisterpagecommand{#1}{#2}{#3}%
+ \dostoptagged
\registeronepagerangeseparator
- \withregisterpagecommand{#4}{#5}{#6}}
+ \dostarttagged\t!registertopage\empty
+ \withregisterpagecommand{#4}{#5}{#6}%
+ \dostoptagged
+ \dostoptagged}
\def\registeroneword#1#2#3% content
{\registerpageseparator
- \registerseeword{#3}}
-
-\def\defaultregisterentry #1{\registerparameter\c!textcommand{\limitedregisterentry{\registerparameter\c!deeptextcommand{#1}}}}
-\def\defaultregisterseeword#1{\labeltexts\v!see{#1}}
+ \dostarttagged\t!registersee\empty
+ \registerseeword{#3}%
+ \dostoptagged}
+
+\def\defaultregisterentry#1%
+ {\dostarttagged\t!registerentry\empty
+ \registerparameter\c!textcommand{\limitedregisterentry{\registerparameter\c!deeptextcommand{#1}}}%
+ \dostoptagged}
+
+\def\defaultregisterseeword#1%
+ {\dostarttagged\t!registersee\empty
+ \labeltexts\v!see{#1}%
+ \dostoptagged}
\let\registerseeword \defaultregisterseeword
\let\registerentry \defaultregisterentry
diff --git a/tex/context/base/strc-sbe.mkiv b/tex/context/base/strc-sbe.mkiv
index 206ac8a9c..8497c37bb 100644
--- a/tex/context/base/strc-sbe.mkiv
+++ b/tex/context/base/strc-sbe.mkiv
@@ -61,11 +61,13 @@
% TODO \resetsectionmarks\zerosection
\getstructureblockenvironment\currentstructureblock
\structureblockparameter\c!before % don't move
+ \dostarttagged\t!division\currentstructureblock
\to \everybeforestructureblock
\appendtoks
\structureblockparameter\c!after % don't move
\doifsomething{\structureblockparameter\c!page}{\page[\structureblockparameter\c!page]}%
+ \dostoptagged
% TODO \resetsectionmarks\zerosection
\to \everyafterstructureblock
diff --git a/tex/context/base/strc-sec.mkiv b/tex/context/base/strc-sec.mkiv
index 1968cbae9..2dd602448 100644
--- a/tex/context/base/strc-sec.mkiv
+++ b/tex/context/base/strc-sec.mkiv
@@ -255,6 +255,7 @@
\def\dostopstructurehead[#1]%
{%\globalpopmacro\currentstructurehead
\xdef\currentstructurehead{#1}% recover
+ \dostoptagged\dostoptagged
\the\everyafterstructurehead}
\def\donextstructurehead[#1][#2][#3]%
@@ -357,13 +358,18 @@
% \unexpanded\def\fullstructureheadnumber{\labeltexts{\structureheadparameter\c!label}{\structurenumber}} % todo
\unexpanded\def\fullstructureheadnumber
- {\edef\currentstructureheadlabeltag{\currentstructureblock\c!label}%
- \labeltexts{\structureheadparameter\currentstructureheadlabeltag}{\structurenumber}}
+ {\edef\currentstructureheadlabeltag{\currentstructureblock\c!label}%
+ \dostarttagged\t!structurenumber\empty
+ \labeltexts{\structureheadparameter\currentstructureheadlabeltag}{\structurenumber}%
+ \dostoptagged}
% \def\fullstructureheadtitle {\structurevariable{titledata.title}} % no catcode!
% \unexpanded\def\fullstructureheadtitle{\structureautocatcodedget{titledata.title}{\structureheadparameter\s!catcodes}}
-\unexpanded\def\fullstructureheadtitle{\ctxlua{structure.sections.title()}}
+\unexpanded\def\fullstructureheadtitle
+ {\dostarttagged\t!structuretitle\empty
+ \ctxlua{structure.sections.title()}%
+ \dostoptagged}
\let\currentstructurehead \empty
\let\currentstructureheadcoupling\empty
@@ -516,6 +522,7 @@
\flushingcolumnfloatstrue
\setfalse\ignorehandlepagebreak
% ignorespaces prevents spaces creeping in when after=\dontleavehmode
+ \dostarttagged\t!structurecontent\empty
\ifconditional\structureheadisdisplay % \ifdisplaysectionhead
\ignorespaces
\else
@@ -567,12 +574,14 @@
\def\dostructureheadspacingbeforeyes
{\docheckstructureheadbefore
\dohandlestructureheadpagebreak
- \structureheadparameter\c!inbetween}
+ \structureheadparameter\c!inbetween
+ \dostarttagged\t!structure\currentstructurehead}
\def\dostructureheadspacingbeforenop
{\docheckstructureheadbefore
\docheckstructureheadlayout
- \structureheadparameter\c!inbetween}
+ \structureheadparameter\c!inbetween
+ \dostarttagged\currentstructurehead\empty}
% \def\emptystructureheadcorrection
% {\ifconditional\structureheadleaveempty % inlined \emptyheadcorrection (with after=\blank)
@@ -661,7 +670,7 @@
% \ifpagebreakdisabled
% \global\pagebreakdisabledfalse
% \else
- \dopreventbreakafterstructureheadauto
+% \dopreventbreakafterstructureheadauto % not ok as it binds the prev par
% \fi
\doif{\structureheadparameter\c!aligntitle}\v!float\indent
\global\precedingstructurelevel\currentstructureheadlevel
diff --git a/tex/context/base/strc-tag.lua b/tex/context/base/strc-tag.lua
new file mode 100644
index 000000000..4381fc529
--- /dev/null
+++ b/tex/context/base/strc-tag.lua
@@ -0,0 +1,85 @@
+if not modules then modules = { } end modules ['strc-tag'] = {
+ version = 1.001,
+ comment = "companion to strc-tag.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This is rather experimental code.
+
+local insert, remove, unpack, concat = table.insert, table.remove, table.unpack, table.concat
+local gsub, find, topattern, format = string.gsub, string.find, string.topattern, string.format
+local lpegmatch = lpeg.match
+local texattribute = tex.attribute
+local unsetvalue = attributes.unsetvalue
+
+structure.tags = structure.tags or { }
+
+local report_tags = logs.new("tags")
+
+local trace_tags = false trackers.register("structure.tags", function(v) trace_tags = v end)
+
+local a_tagged = attributes.private('tagged')
+local a_image = attributes.private('image')
+
+local tags, labels, stack, chain, ids, enabled = { }, { }, { }, { }, { }, false -- no grouping assumed
+
+structure.tags.taglist = tags -- can best be hidden
+
+function structure.tags.start(tag,label,detail)
+ labels[label or tag] = tag
+ if detail and detail ~= "" then
+ tag = tag .. ":" .. detail
+ end
+ if not enabled then
+ backends.codeinjections.enabletags(tags,labels)
+ enabled = true
+ end
+ local n = (ids[tag] or 0) + 1
+ ids[tag] = n
+ chain[#chain+1] = tag .. "-" .. n -- insert(chain,tag .. ":" .. n)
+ local t = #tags + 1
+ stack[#stack+1] = t -- insert(stack,t)
+ tags[t] = { unpack(chain) } -- we can add key values for alt and actualtext if needed
+ texattribute[a_tagged] = t
+ return t
+end
+
+function structure.tags.stop()
+ local t = stack[#stack] stack[#stack] = nil -- local t = remove(stack)
+ if not t then
+ if trace_tags then
+ report_tags("ignoring end tag, previous chain: %s",#chain > 0 and concat(chain[#chain]) or "none")
+ end
+ t = unsetvalue
+ else
+ chain[#chain] = nil -- remove(chain)
+ end
+ texattribute[a_tagged] = t
+ return t
+end
+
+function structure.atlocation(str)
+ local location = gsub(concat(tags[texattribute[a_tagged]],"-"),"%-%d+","")
+ return find(location,topattern(str)) ~= nil
+end
+
+function structure.tags.handler(head) -- we need a dummy
+ return head, false
+end
+
+statistics.register("structure elements", function()
+ if enabled then
+ return format("%s element chains identified",#tags)
+ else
+ return nil
+ end
+end)
+
+directives.register("backend.addtags", function(v)
+ if not enabled then
+ backends.codeinjections.enabletags(tags,labels)
+ enabled = true
+ end
+end)
diff --git a/tex/context/base/strc-tag.mkiv b/tex/context/base/strc-tag.mkiv
new file mode 100644
index 000000000..53323050a
--- /dev/null
+++ b/tex/context/base/strc-tag.mkiv
@@ -0,0 +1,192 @@
+%D \module
+%D [ file=strc-tag,
+%D version=2010.07.16,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Tags,
+%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.
+
+% key/values and other names might change (and probably will)
+
+\writestatus{loading}{ConTeXt Structure Macros / Tags}
+
+\registerctxluafile{strc-tag}{1.001}
+
+\unprotect
+
+% labels: temporary here
+
+\def\t!document {document} % Div
+
+\def\t!division {division} % Div
+\def\t!paragraph {paragraph} % P
+\def\t!construct {construct} % Span
+
+\def\t!structure {structure} % Sect
+\def\t!structuretitle {structuretitle} % H
+\def\t!structurenumber {structurenumber} % H
+\def\t!structurecontent {structurecontent} % Div
+
+\def\t!itemgroup {itemgroup} % L
+\def\t!item {item} % Li
+\def\t!itemtag {itemtag} % Lbl
+\def\t!itemcontent {itemcontent} % LBody
+
+\def\t!description {description} % Li
+\def\t!descriptiontag {descriptiontag} % Lbl
+\def\t!descriptioncontent{descriptioncontent} % LBody
+
+\def\t!verbatimblock {verbatimblock} % Code
+\def\t!verbatim {verbatim} % Code
+
+\def\t!register {register} % Div
+\def\t!registersection {registersection} % Div
+\def\t!registertag {registertag} % Span
+\def\t!registerentries {registerentries} % Div
+\def\t!registerentry {registerentry} % Span
+\def\t!registersee {registersee} % Span
+\def\t!registerpages {registerpages} % Span
+\def\t!registerpage {registerpage} % Span
+
+\def\t!table {table} % Table
+\def\t!tablerow {tr} % TR
+\def\t!tablecell {td} % TD
+\def\t!tabulate {tabulate} % Table
+\def\t!tabulaterow {row} % TR
+\def\t!tabulatecell {cell} % TD
+
+\def\t!list {list} % TOC
+\def\t!listitem {listitem} % TOCI
+\def\t!listtag {listtag} % Lbl
+\def\t!listcontent {listcontent} % P
+\def\t!listdata {listdata} % P
+\def\t!listpage {listpage} % Reference
+
+\def\t!delimitedblock {delimited} % BlockQuote
+\def\t!delimited {delimited} % Quote
+\def\t!subsentence {subsentence} % Span
+
+\def\t!float {float} % Div
+\def\t!floatcaption {floatcaption} % Caption
+\def\t!floattag {floattag} % Span
+\def\t!floattext {floattext} % Span
+\def\t!floatcontent {floatcontent} % P
+
+\def\t!image {image} % P
+
+\def\t!mpgraphic {mpgraphic} % P
+
+\def\t!formulaset {formulaset} % Div
+\def\t!formula {formula} % Div
+\def\t!formulatag {formulatag} % Span
+\def\t!formulacontent {formulacontent} % P
+\def\t!subformula {subformula} % Div
+
+\def\t!link {link} % Link
+
+% \setuptaglabeltext
+% [en]
+% [\t!document=document]
+
+% the real code
+
+\definesystemattribute[tagged] \chardef\taggedattribute \dogetattributeid{tagged}
+\definesystemattribute[image] \chardef\imageattribute \dogetattributeid{image}
+
+% \def\mapelementtobackendtag {\dodoubleargument\domapelementtobackendtag}
+% \def\domapelementtobackendtag[#1][#2]{\ctxlua{backends.codeinjections.maptag("#1","#2")}}
+
+% todo: indirect macro for trialtypesetting
+
+\unexpanded\def\dostartelement{\iftrialtypesetting\expandafter\noostartelement\else\expandafter\dodostartelement\fi}
+\unexpanded\def\dostopelement {\iftrialtypesetting \else\expandafter\dodostopelement \fi}
+
+\unexpanded\def\dodostartelement[#1]{\ctxlua{structure.tags.start("#1","\dogetupsometaglabeltext{#1}")}}
+\unexpanded\def\dodostopelement {\ctxlua{structure.tags.stop()}}
+
+\unexpanded\def\nostartelement[#1]{}
+\unexpanded\def\nostopelement {}
+
+% beware: making this one unexpanded spoils tables (noalign problem)
+
+\def\dodostarttagged{\iftrialtypesetting\expandafter\nodostarttagged\else\expandafter\dododostarttagged\fi}
+\def\dodostoptagged {\iftrialtypesetting \else\expandafter\dododostoptagged \fi}
+
+\def\dododostarttagged#1#2{\ctxlua{structure.tags.start("#1","\dogetupsometaglabeltext{#1}","#2")}}
+\def\dododostoptagged {\ctxlua{structure.tags.stop()}}
+
+\def\nodostarttagged#1#2{}
+\def\nodostoptagged {}
+
+\newtoks\everysetupstructure
+
+\def\setupstructure[#1]%
+ {\getparameters[\??el][#1]%
+ \the\everysetupstructure}
+
+\def\doenableelements
+ {\setuplanguage[\s!default][\s!righthyphenchar="AD]% for the moment here
+ \let\startelement\dostartelement
+ \let\stopelement \dostopelement}
+
+\def\dodisableelements
+ {\let\startelement\nostartelement
+ \let\stopelement \nostopelement}
+
+\def\doenabletagged
+ {\let\dostarttagged\dodostarttagged
+ \let\dostoptagged \dodostoptagged }
+
+\def\dodisabletagged
+ {\let\dostarttagged\nodostarttagged
+ \let\dostoptagged \nodostoptagged }
+
+\newtoks\everyenableelements
+\newtoks\everydisableelements
+
+\appendtoks
+ \doenableelements
+ \doifelse\@@elmethod\v!auto\doenabletagged\dodisabletagged
+\to \everyenableelements
+
+\appendtoks
+ \dodisableelements
+ \dodisabletagged
+\to \everydisableelements
+
+\appendtoks
+ \doifelse\@@elstate\v!start{\the\everyenableelements}{\the\everydisableelements}%
+\to \everysetupstructure
+
+\setupstructure
+ [\c!state=\v!stop,
+ \c!method=\v!auto]
+
+\unexpanded\def\startparagraph
+ {\dostarttagged\t!paragraph\empty}
+
+\unexpanded\def\stopparagraph
+ {\dostoptagged
+ \par}
+
+\appendtoks
+ \dostarttagged\t!document\empty
+\to \everystarttext
+
+\appendtoks
+ \dostoptagged
+\to \everystoptext
+
+% \doifinelementelse{structure:section} {yes} {no}
+% \doifinelementelse{structure:chapter} {yes} {no}
+% \doifinelementelse{division:*-structure:chapter} {yes} {no}
+
+\def\doifinelementelse#1%
+ {\ctxlua{commands.testcase(structure.atlocation("#1"))}}
+
+\protect
diff --git a/tex/context/base/tabl-ntb.mkiv b/tex/context/base/tabl-ntb.mkiv
index b24eaa85d..67d20a615 100644
--- a/tex/context/base/tabl-ntb.mkiv
+++ b/tex/context/base/tabl-ntb.mkiv
@@ -671,7 +671,7 @@
\executeifdefined{\@@rawtblprefix\v!start\v!oddeven\TBLlevel}\relax
\executeifdefined{\@@rawtblprefix\v!start\number\TBLlevel}\relax}
-\def\bTABLE
+\unexpanded\def\bTABLE
{\dosingleempty\dobTABLE}
\def\dobTABLE[#1]%
@@ -726,7 +726,7 @@
\unexpanded\def\eTH{\ignorespaces}
\unexpanded\def\eTN{\ignorespaces}
-\def\eTABLE % beware, we need to get rid of spurious spaces when in hmode
+\unexpanded\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
@@ -900,18 +900,35 @@
\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}
+
\def\begintbl
{\global\tblspn\zerocount
\global\tblcol\zerocount
\global\tblrow\zerocount
\global\advance\tblrow\minusone
\tabskip\zeropoint
+ \dostarttagged\t!table\empty
+ \dostarttagged\t!tablerow\empty
+ \appendtoks\dostoptagged\dostarttagged\t!tablerow\empty\to\everycr
\halign\bgroup
\registerparoptions % new
- \ignorespaces##\unskip&&\ignorespaces##\unskip\cr}
+ \ignorespaces##\unskip&&\dostarttagged\t!tablecell\empty\ignorespaces##\unskip\dostoptagged\cr}
\def\endtbl
- {\egroup}
+ {\dostoptagged\egroup
+ \dostoptagged}
\setvalue{\tblnone TBL}#1#2%
{\spanTBL{#1}{#2}}
diff --git a/tex/context/base/tabl-tbl.mkiv b/tex/context/base/tabl-tbl.mkiv
index 400d8a659..007338146 100644
--- a/tex/context/base/tabl-tbl.mkiv
+++ b/tex/context/base/tabl-tbl.mkiv
@@ -348,6 +348,7 @@
\bgroup
\noexpand\bbskip
\bgroup % we cannot combine the if because a cell may have only one ##
+\noexpand\dostarttagged\noexpand\t!tabulatecell\noexpand\empty
\noexpand#1%
\ifcase\tabulatereshape\else
\beginreshapedtabulatepar
@@ -373,6 +374,7 @@
\endreshapedtabulatepar
\fi
\noexpand#2%
+\noexpand\dostoptagged
\egroup
\egroup
&\noexpand\posttabrule\hskip\postabskip##%
@@ -1370,7 +1372,12 @@
\setbox\tabulatebox\vbox \bgroup
\fi
%
+\dostarttagged\t!tabulate\empty
+\dostarttagged\t!tabulaterow\empty
+\appendtoks\dostoptagged\dostarttagged\t!tabulaterow\empty\to\everycr
\@EA\halign\@EA{\the\!!toksa\crcr\fulltabulatecontent\crcr}%
+\dostoptagged
+\dostoptagged
\prevdepth\strutdp % nog eens beter, temporary hack
\doifvalue{\??tt\currenttabulate\c!distance}\v!grid{\vskip-\strutdp}% experimental tm-prikkels
%
diff --git a/tex/context/base/task-ini.lua b/tex/context/base/task-ini.lua
index 0706fa322..4c5ac401d 100644
--- a/tex/context/base/task-ini.lua
+++ b/tex/context/base/task-ini.lua
@@ -39,6 +39,8 @@ tasks.appendaction("shipouts", "normalizers", "nodes.add_references")
tasks.appendaction("shipouts", "normalizers", "nodes.add_destinations") -- disabled
tasks.appendaction("shipouts", "normalizers", "nodes.rules.process") -- disabled
tasks.appendaction("shipouts", "normalizers", "nodes.shifts.process") -- disabled
+tasks.appendaction("shipouts", "normalizers", "structure.tags.handler") -- disabled
+tasks.appendaction("shipouts", "normalizers", "nodes.accessibility.handler") -- disabled
tasks.appendaction("shipouts", "finishers", "shipouts.handle_color") -- disabled
tasks.appendaction("shipouts", "finishers", "shipouts.handle_transparency") -- disabled
@@ -50,6 +52,8 @@ tasks.appendaction("shipouts", "finishers", "shipouts.handle_viewerlayer")
tasks.appendaction("math", "normalizers", "noads.relocate_characters", nil, "nohead") -- always on
tasks.appendaction("math", "normalizers", "noads.resize_characters", nil, "nohead") -- always on
tasks.appendaction("math", "normalizers", "noads.respace_characters", nil, "nohead") -- always on
+tasks.appendaction("math", "normalizers", "noads.check_alternates", nil, "nohead") -- always on
+tasks.appendaction("math", "normalizers", "noads.add_tags", nil, "nohead") -- disabled
tasks.appendaction("math", "builders", "noads.mlist_to_hlist") -- always on
@@ -86,6 +90,8 @@ tasks.disableaction("shipouts", "shipouts.handle_colorintent")
tasks.disableaction("shipouts", "shipouts.handle_effect")
tasks.disableaction("shipouts", "shipouts.handle_negative")
tasks.disableaction("shipouts", "shipouts.handle_viewerlayer")
+tasks.disableaction("shipouts", "structure.tags.handler")
+tasks.disableaction("shipouts", "nodes.accessibility.handler")
tasks.disableaction("shipouts", "nodes.add_references")
tasks.disableaction("shipouts", "nodes.add_destinations")
@@ -95,6 +101,8 @@ tasks.disableaction("mvlbuilders", "nodes.migrate_outwards")
tasks.disableaction("processors", "parbuilders.solutions.splitters.split")
tasks.disableaction("finalizers", "parbuilders.solutions.splitters.optimize")
+tasks.disableaction("math", "noads.add_tags")
+
callbacks.freeze("find_.*_file", "find file using resolver")
callbacks.freeze("read_.*_file", "read file at once")
callbacks.freeze("open_.*_file", "open file for reading")
diff --git a/tex/context/base/trac-deb.lua b/tex/context/base/trac-deb.lua
index 109d84612..51b98c7f3 100644
--- a/tex/context/base/trac-deb.lua
+++ b/tex/context/base/trac-deb.lua
@@ -122,11 +122,21 @@ function tracers.printerror(offset)
end
end
-function tracers.texerrormessage(...) -- for the moment we put this function here
- local v = format(...)
- tex.sprint(tex.ctxcatcodes,"\\errmessage{")
- tex.sprint(tex.vrbcatcodes,v)
- tex.print(tex.ctxcatcodes,"}")
+if tex.error then
+
+ function tracers.texerrormessage(...) -- for the moment we put this function here
+ tex.error(format(...), { })
+ end
+
+else
+
+ function tracers.texerrormessage(...) -- for the moment we put this function here
+ local v = format(...)
+ tex.sprint(tex.ctxcatcodes,"\\errmessage{")
+ tex.sprint(tex.vrbcatcodes,v)
+ tex.print(tex.ctxcatcodes,"}")
+ end
+
end
directives.register("system.errorcontext", function(v)
diff --git a/tex/context/base/trac-lmx.mkiv b/tex/context/base/trac-lmx.mkiv
deleted file mode 100644
index a47d2b8bb..000000000
--- a/tex/context/base/trac-lmx.mkiv
+++ /dev/null
@@ -1,16 +0,0 @@
-%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/type-ini.mkiv b/tex/context/base/type-ini.mkiv
index 4698a39be..8fb2c077a 100644
--- a/tex/context/base/type-ini.mkiv
+++ b/tex/context/base/type-ini.mkiv
@@ -403,12 +403,12 @@
\def\typefaceencoding{\defaultencoding}
\def\dostarttypefacedefining#1#2#3%
- {\geteparameters[\??ts][\s!rscale=\plusone,\s!features=,\s!fallbacks=,#3]%
+ {\geteparameters[\??ts][\s!rscale=\plusone,\s!features=,\s!fallbacks=,\s!goodies=,#3]%
\pushmacro\fontclass
\setcurrentfontclass{#1}%
\pushmacro\relativefontsize
\let\relativefontsize\@@tsrscale % still needed ?
- \savefontclassparameters{#2}\@@tsrscale\@@tsfeatures\@@tsfallbacks}
+ \savefontclassparameters{#2}\@@tsrscale\@@tsfeatures\@@tsfallbacks\@@tsgoodies}
\def\dostoptypefacedefining
{\popmacro\relativefontsize
diff --git a/tex/context/base/type-otf.mkiv b/tex/context/base/type-otf.mkiv
index eacded942..b889e1ad2 100644
--- a/tex/context/base/type-otf.mkiv
+++ b/tex/context/base/type-otf.mkiv
@@ -1834,10 +1834,13 @@
\starttypescriptcollection[xits]
% This one makes more sense. Xits uses the glyph collection from stix but packages
- % it in a proper OpenType Math font.
+ % it in a proper OpenType Math font. From the Stix site: Version 1.1, which will
+ % include fonts packaged for use with Microsoft Office applications, is scheduled
+ % for release by the end of 2010. Version 1.2, which will include Type 1 fonts for
+ % use with LaTeX, will follow in 2011. So, we are on our own anyway.
\starttypescript [math] [xits] [name]
- \definefontsynonym[MathRoman][file:xits-math.otf][\s!features=\s!math\mathsizesuffix]
+ \definefontsynonym[MathRoman][file:xits-math.otf][\s!features=\s!math\mathsizesuffix,\s!goodies=xits-math]
\stoptypescript
\starttypescript [serif] [xits] [name]
diff --git a/tex/context/base/x-mathml.mkiv b/tex/context/base/x-mathml.mkiv
index 4d093a463..5e1046272 100644
--- a/tex/context/base/x-mathml.mkiv
+++ b/tex/context/base/x-mathml.mkiv
@@ -2286,6 +2286,12 @@
\ctxlua{lxml.mml.mmultiscripts("#1")}
\stopxmlsetups
+% goodie
+
+\definebuffer[mml]
+
+\def\stopmml{\xmlprocessbuffer{@mml@}{\thedefinedbuffer{mml}}{}}
+
\stopmodule
\protect \endinput
diff --git a/tex/context/fonts/xits-math.lfg b/tex/context/fonts/xits-math.lfg
new file mode 100644
index 000000000..84e569e5f
--- /dev/null
+++ b/tex/context/fonts/xits-math.lfg
@@ -0,0 +1,12 @@
+return {
+ name = "xits-math",
+ version = "1.00",
+ comment = "Goodies that complement xits.",
+ author = "Hans Hagen",
+ copyright = "ConTeXt development team",
+ mathematics = {
+ alternates = {
+ cal = { feature = 'ss01', value = 1, comment = "alternative calligraphic shapes" },
+ }
+ }
+}
diff --git a/tex/context/interface/keys-cs.xml b/tex/context/interface/keys-cs.xml
index 93d81caa6..40d5f2fae 100644
--- a/tex/context/interface/keys-cs.xml
+++ b/tex/context/interface/keys-cs.xml
@@ -93,6 +93,7 @@
<cd:variable name='bib' value='bib'/>
<cd:variable name='big' value='velke'/>
<cd:variable name='bigbodyfont' value='bigbodyfont'/>
+ <cd:variable name='bigger' value='bigger'/>
<cd:variable name='bigpreference' value='vysokapriorita'/>
<cd:variable name='blank' value='prazdny'/>
<cd:variable name='blockquote' value='blockquote'/>
@@ -367,6 +368,7 @@
<cd:variable name='random' value='nahodny'/>
<cd:variable name='readonly' value='pouzeprocteni'/>
<cd:variable name='rectangular' value='pravouhly'/>
+ <cd:variable name='reference' value='odkaz'/>
<cd:variable name='referral' value='znacka'/>
<cd:variable name='register' value='rejstrik'/>
<cd:variable name='regular' value='pravidelne'/>
@@ -414,6 +416,7 @@
<cd:variable name='smallbolditalic' value='maletucnekurzivni'/>
<cd:variable name='smallboldslanted' value='maletucnesklonene'/>
<cd:variable name='smallcaps' value='kapitalky'/>
+ <cd:variable name='smaller' value='smaller'/>
<cd:variable name='smallitalic' value='malekurzivni'/>
<cd:variable name='smallitalicbold' value='malekurzivnitucne'/>
<cd:variable name='smallnormal' value='malenormalni'/>
diff --git a/tex/context/interface/keys-de.xml b/tex/context/interface/keys-de.xml
index 4c60d2be4..4ded5c635 100644
--- a/tex/context/interface/keys-de.xml
+++ b/tex/context/interface/keys-de.xml
@@ -93,6 +93,7 @@
<cd:variable name='bib' value='bib'/>
<cd:variable name='big' value='gross'/>
<cd:variable name='bigbodyfont' value='bigbodyfont'/>
+ <cd:variable name='bigger' value='bigger'/>
<cd:variable name='bigpreference' value='grosszuegig'/>
<cd:variable name='blank' value='blanko'/>
<cd:variable name='blockquote' value='blockquote'/>
@@ -367,6 +368,7 @@
<cd:variable name='random' value='zufaellig'/>
<cd:variable name='readonly' value='nurlesbar'/>
<cd:variable name='rectangular' value='rechteckig'/>
+ <cd:variable name='reference' value='referenz'/>
<cd:variable name='referral' value='merkmal'/>
<cd:variable name='register' value='register'/>
<cd:variable name='regular' value='regular'/>
@@ -414,6 +416,7 @@
<cd:variable name='smallbolditalic' value='kleinfettitalic'/>
<cd:variable name='smallboldslanted' value='kleinfettgeneigt'/>
<cd:variable name='smallcaps' value='smallcaps'/>
+ <cd:variable name='smaller' value='smaller'/>
<cd:variable name='smallitalic' value='kleinitalic'/>
<cd:variable name='smallitalicbold' value='kleinitalicfett'/>
<cd:variable name='smallnormal' value='kleinnormal'/>
diff --git a/tex/context/interface/keys-en.xml b/tex/context/interface/keys-en.xml
index 26ee20ad3..995f53c93 100644
--- a/tex/context/interface/keys-en.xml
+++ b/tex/context/interface/keys-en.xml
@@ -93,6 +93,7 @@
<cd:variable name='bib' value='bib'/>
<cd:variable name='big' value='big'/>
<cd:variable name='bigbodyfont' value='bigbodyfont'/>
+ <cd:variable name='bigger' value='bigger'/>
<cd:variable name='bigpreference' value='bigpreference'/>
<cd:variable name='blank' value='blank'/>
<cd:variable name='blockquote' value='blockquote'/>
@@ -367,6 +368,7 @@
<cd:variable name='random' value='random'/>
<cd:variable name='readonly' value='readonly'/>
<cd:variable name='rectangular' value='rectangular'/>
+ <cd:variable name='reference' value='reference'/>
<cd:variable name='referral' value='referral'/>
<cd:variable name='register' value='register'/>
<cd:variable name='regular' value='regular'/>
@@ -414,6 +416,7 @@
<cd:variable name='smallbolditalic' value='smallbolditalic'/>
<cd:variable name='smallboldslanted' value='smallboldslanted'/>
<cd:variable name='smallcaps' value='smallcaps'/>
+ <cd:variable name='smaller' value='smaller'/>
<cd:variable name='smallitalic' value='smallitalic'/>
<cd:variable name='smallitalicbold' value='smallitalicbold'/>
<cd:variable name='smallnormal' value='smallnormal'/>
diff --git a/tex/context/interface/keys-fr.xml b/tex/context/interface/keys-fr.xml
index ba6483365..3e52b484e 100644
--- a/tex/context/interface/keys-fr.xml
+++ b/tex/context/interface/keys-fr.xml
@@ -93,6 +93,7 @@
<cd:variable name='bib' value='bib'/>
<cd:variable name='big' value='grand'/>
<cd:variable name='bigbodyfont' value='grandepolicecorp'/>
+ <cd:variable name='bigger' value='bigger'/>
<cd:variable name='bigpreference' value='grandepreference'/>
<cd:variable name='blank' value='vide'/>
<cd:variable name='blockquote' value='blockquote'/>
@@ -367,6 +368,7 @@
<cd:variable name='random' value='aleatoire'/>
<cd:variable name='readonly' value='lectureseule'/>
<cd:variable name='rectangular' value='rectangulaire'/>
+ <cd:variable name='reference' value='reference'/>
<cd:variable name='referral' value='referral'/>
<cd:variable name='register' value='registre'/>
<cd:variable name='regular' value='regulier'/>
@@ -414,6 +416,7 @@
<cd:variable name='smallbolditalic' value='italiquegraspetit'/>
<cd:variable name='smallboldslanted' value='inclinegraspetit'/>
<cd:variable name='smallcaps' value='petitescapitales'/>
+ <cd:variable name='smaller' value='smaller'/>
<cd:variable name='smallitalic' value='italiquepetit'/>
<cd:variable name='smallitalicbold' value='grasitaliquepetit'/>
<cd:variable name='smallnormal' value='normalpetit'/>
diff --git a/tex/context/interface/keys-it.xml b/tex/context/interface/keys-it.xml
index 098aba899..944dea0e9 100644
--- a/tex/context/interface/keys-it.xml
+++ b/tex/context/interface/keys-it.xml
@@ -93,6 +93,7 @@
<cd:variable name='bib' value='bib'/>
<cd:variable name='big' value='grande'/>
<cd:variable name='bigbodyfont' value='grossofontdeltesto'/>
+ <cd:variable name='bigger' value='bigger'/>
<cd:variable name='bigpreference' value='grandepreferenza'/>
<cd:variable name='blank' value='rigovuoto'/>
<cd:variable name='blockquote' value='blockquote'/>
@@ -367,6 +368,7 @@
<cd:variable name='random' value='casuale'/>
<cd:variable name='readonly' value='solalettura'/>
<cd:variable name='rectangular' value='rettangolare'/>
+ <cd:variable name='reference' value='riferimento'/>
<cd:variable name='referral' value='referral'/>
<cd:variable name='register' value='registro'/>
<cd:variable name='regular' value='regolare'/>
@@ -414,6 +416,7 @@
<cd:variable name='smallbolditalic' value='piccolograssettocorsivo'/>
<cd:variable name='smallboldslanted' value='piccolograssettoinclinato'/>
<cd:variable name='smallcaps' value='maiuscoletto'/>
+ <cd:variable name='smaller' value='smaller'/>
<cd:variable name='smallitalic' value='piccolocorsivo'/>
<cd:variable name='smallitalicbold' value='piccolocorsivograssetto'/>
<cd:variable name='smallnormal' value='piccolonormale'/>
diff --git a/tex/context/interface/keys-nl.xml b/tex/context/interface/keys-nl.xml
index d9eb33410..30044d0f1 100644
--- a/tex/context/interface/keys-nl.xml
+++ b/tex/context/interface/keys-nl.xml
@@ -93,6 +93,7 @@
<cd:variable name='bib' value='bib'/>
<cd:variable name='big' value='groot'/>
<cd:variable name='bigbodyfont' value='grootkorps'/>
+ <cd:variable name='bigger' value='groter'/>
<cd:variable name='bigpreference' value='grotevoorkeur'/>
<cd:variable name='blank' value='blanko'/>
<cd:variable name='blockquote' value='blokcitaat'/>
@@ -367,6 +368,7 @@
<cd:variable name='random' value='willekeurig'/>
<cd:variable name='readonly' value='alleenleesbaar'/>
<cd:variable name='rectangular' value='recht'/>
+ <cd:variable name='reference' value='referentie'/>
<cd:variable name='referral' value='kenmerk'/>
<cd:variable name='register' value='register'/>
<cd:variable name='regular' value='regular'/>
@@ -414,6 +416,7 @@
<cd:variable name='smallbolditalic' value='kleinvetitalic'/>
<cd:variable name='smallboldslanted' value='kleinvetschuin'/>
<cd:variable name='smallcaps' value='smallcaps'/>
+ <cd:variable name='smaller' value='kleiner'/>
<cd:variable name='smallitalic' value='kleinitalic'/>
<cd:variable name='smallitalicbold' value='kleinitalicvet'/>
<cd:variable name='smallnormal' value='kleinnormaal'/>
diff --git a/tex/context/interface/keys-pe.xml b/tex/context/interface/keys-pe.xml
index 2b0a3f25b..543880d25 100644
--- a/tex/context/interface/keys-pe.xml
+++ b/tex/context/interface/keys-pe.xml
@@ -93,6 +93,7 @@
<cd:variable name='bib' value='bib'/>
<cd:variable name='big' value='بزرگ'/>
<cd:variable name='bigbodyfont' value='قلم‌بدنه‌بزرگ'/>
+ <cd:variable name='bigger' value='bigger'/>
<cd:variable name='bigpreference' value='اولویت‌بزرگ'/>
<cd:variable name='blank' value='خالی'/>
<cd:variable name='blockquote' value='نقل‌بلوک'/>
@@ -367,6 +368,7 @@
<cd:variable name='random' value='تصادفی'/>
<cd:variable name='readonly' value='تنهاخواندنی'/>
<cd:variable name='rectangular' value='چهارگوشه'/>
+ <cd:variable name='reference' value='مرجع'/>
<cd:variable name='referral' value='مراجعه'/>
<cd:variable name='register' value='ثبت'/>
<cd:variable name='regular' value='منظم'/>
@@ -414,6 +416,7 @@
<cd:variable name='smallbolditalic' value='ایتالیک‌مشکی‌کوچک'/>
<cd:variable name='smallboldslanted' value='خوابیده‌مشکی‌کوچک'/>
<cd:variable name='smallcaps' value='smallcaps'/>
+ <cd:variable name='smaller' value='smaller'/>
<cd:variable name='smallitalic' value='ایتالیک‌کوچک'/>
<cd:variable name='smallitalicbold' value='مشکی‌ایتالیک‌کوچک'/>
<cd:variable name='smallnormal' value='نرمال‌کوچک'/>
diff --git a/tex/context/interface/keys-ro.xml b/tex/context/interface/keys-ro.xml
index 46f2ecd1e..b5d98845f 100644
--- a/tex/context/interface/keys-ro.xml
+++ b/tex/context/interface/keys-ro.xml
@@ -93,6 +93,7 @@
<cd:variable name='bib' value='bib'/>
<cd:variable name='big' value='mare'/>
<cd:variable name='bigbodyfont' value='bigbodyfont'/>
+ <cd:variable name='bigger' value='bigger'/>
<cd:variable name='bigpreference' value='preferintamare'/>
<cd:variable name='blank' value='blank'/>
<cd:variable name='blockquote' value='blockquote'/>
@@ -367,6 +368,7 @@
<cd:variable name='random' value='aleator'/>
<cd:variable name='readonly' value='readonly'/>
<cd:variable name='rectangular' value='rectangular'/>
+ <cd:variable name='reference' value='referinta'/>
<cd:variable name='referral' value='referinta'/>
<cd:variable name='register' value='registru'/>
<cd:variable name='regular' value='regular'/>
@@ -414,6 +416,7 @@
<cd:variable name='smallbolditalic' value='micaldininclinat'/>
<cd:variable name='smallboldslanted' value='micaldininclinat'/>
<cd:variable name='smallcaps' value='majusculemici'/>
+ <cd:variable name='smaller' value='smaller'/>
<cd:variable name='smallitalic' value='micitalic'/>
<cd:variable name='smallitalicbold' value='micitalicaldin'/>
<cd:variable name='smallnormal' value='micnormal'/>
diff --git a/tex/generic/context/luatex-fonts-merged.lua b/tex/generic/context/luatex-fonts-merged.lua
index 6fd20b1e9..3f96aa593 100644
--- a/tex/generic/context/luatex-fonts-merged.lua
+++ b/tex/generic/context/luatex-fonts-merged.lua
@@ -1,6 +1,6 @@
-- merged file : luatex-fonts-merged.lua
-- parent file : luatex-fonts.lua
--- merge date : 07/15/10 15:01:32
+-- merge date : 07/30/10 11:35:46
do -- begin closure to overcome local limits and interference
@@ -3112,6 +3112,8 @@ fontloader.totable = fontloader.to_table
fonts = fonts or { }
+-- we will also have des and fam hashes
+
fonts.ids = fonts.ids or { } fonts.identifiers = fonts.ids -- aka fontdata
fonts.chr = fonts.chr or { } fonts.characters = fonts.chr -- aka chardata
fonts.qua = fonts.qua or { } fonts.quads = fonts.qua -- aka quaddata
@@ -7535,7 +7537,7 @@ local function prepare_base_substitutions(tfmdata,kind,value) -- we can share so
if pv then
local upv = unicodes[pv]
if upv then
- if type(upv) == "table" then
+ if type(upv) == "table" then -- zero change that table
upv = upv[1]
end
if characters[upv] then
@@ -7563,7 +7565,7 @@ local function prepare_base_substitutions(tfmdata,kind,value) -- we can share so
if pc then
local upc = unicodes[pc]
if upc then
- if type(upc) == "table" then
+ if type(upc) == "table" then -- zero change that table
upc = upc[1]
end
if characters[upc] then
@@ -11257,6 +11259,15 @@ function define.resolve(specification)
else
specification.forced = specification.forced
end
+ -- for the moment here (goodies eset outside features)
+ local goodies = specification.goodies
+ if goodies and goodies ~= "" then
+ local normalgoodies = specification.features.normal.goodies
+ if not normalgoodies or normalgoodies == "" then
+ specification.features.normal.goodies = goodies
+ end
+ end
+ --
specification.hash = lower(specification.name .. ' @ ' .. tfm.hash_features(specification))
if specification.sub and specification.sub ~= "" then
specification.hash = specification.sub .. ' @ ' .. specification.hash