diff options
51 files changed, 5046 insertions, 3773 deletions
diff --git a/context/data/scite/context/lexers/data/scite-context-data-context.lua b/context/data/scite/context/lexers/data/scite-context-data-context.lua index e539ac287..33f583a35 100644 --- a/context/data/scite/context/lexers/data/scite-context-data-context.lua +++ b/context/data/scite/context/lexers/data/scite-context-data-context.lua @@ -1,4 +1,4 @@ return { ["constants"]={ "zerocount", "minusone", "minustwo", "plusone", "plustwo", "plusthree", "plusfour", "plusfive", "plussix", "plusseven", "pluseight", "plusnine", "plusten", "plussixteen", "plushundred", "plusthousand", "plustenthousand", "plustwentythousand", "medcard", "maxcard", "zeropoint", "onepoint", "halfapoint", "onebasepoint", "maxdimen", "scaledpoint", "thousandpoint", "points", "halfpoint", "zeroskip", "zeromuskip", "onemuskip", "pluscxxvii", "pluscxxviii", "pluscclv", "pluscclvi", "normalpagebox", "endoflinetoken", "outputnewlinechar", "emptytoks", "empty", "undefined", "voidbox", "emptybox", "emptyvbox", "emptyhbox", "bigskipamount", "medskipamount", "smallskipamount", "fmtname", "fmtversion", "texengine", "texenginename", "texengineversion", "luatexengine", "pdftexengine", "xetexengine", "unknownengine", "etexversion", "pdftexversion", "xetexversion", "xetexrevision", "activecatcode", "bgroup", "egroup", "endline", "conditionaltrue", "conditionalfalse", "attributeunsetvalue", "uprotationangle", "rightrotationangle", "downrotationangle", "leftrotationangle", "inicatcodes", "ctxcatcodes", "texcatcodes", "notcatcodes", "txtcatcodes", "vrbcatcodes", "prtcatcodes", "nilcatcodes", "luacatcodes", "tpacatcodes", "tpbcatcodes", "xmlcatcodes", "ctdcatcodes", "escapecatcode", "begingroupcatcode", "endgroupcatcode", "mathshiftcatcode", "alignmentcatcode", "endoflinecatcode", "parametercatcode", "superscriptcatcode", "subscriptcatcode", "ignorecatcode", "spacecatcode", "lettercatcode", "othercatcode", "activecatcode", "commentcatcode", "invalidcatcode", "tabasciicode", "newlineasciicode", "formfeedasciicode", "endoflineasciicode", "endoffileasciicode", "spaceasciicode", "hashasciicode", "dollarasciicode", "commentasciicode", "ampersandasciicode", "colonasciicode", "backslashasciicode", "circumflexasciicode", "underscoreasciicode", "leftbraceasciicode", "barasciicode", "rightbraceasciicode", "tildeasciicode", "delasciicode", "lessthanasciicode", "morethanasciicode", "doublecommentsignal", "atsignasciicode", "exclamationmarkasciicode", "questionmarkasciicode", "doublequoteasciicode", "singlequoteasciicode", "forwardslashasciicode", "primeasciicode", "activemathcharcode", "activetabtoken", "activeformfeedtoken", "activeendoflinetoken", "batchmodecode", "nonstopmodecode", "scrollmodecode", "errorstopmodecode", "bottomlevelgroupcode", "simplegroupcode", "hboxgroupcode", "adjustedhboxgroupcode", "vboxgroupcode", "vtopgroupcode", "aligngroupcode", "noaligngroupcode", "outputgroupcode", "mathgroupcode", "discretionarygroupcode", "insertgroupcode", "vcentergroupcode", "mathchoicegroupcode", "semisimplegroupcode", "mathshiftgroupcode", "mathleftgroupcode", "vadjustgroupcode", "charnodecode", "hlistnodecode", "vlistnodecode", "rulenodecode", "insertnodecode", "marknodecode", "adjustnodecode", "ligaturenodecode", "discretionarynodecode", "whatsitnodecode", "mathnodecode", "gluenodecode", "kernnodecode", "penaltynodecode", "unsetnodecode", "mathsnodecode", "charifcode", "catifcode", "numifcode", "dimifcode", "oddifcode", "vmodeifcode", "hmodeifcode", "mmodeifcode", "innerifcode", "voidifcode", "hboxifcode", "vboxifcode", "xifcode", "eofifcode", "trueifcode", "falseifcode", "caseifcode", "definedifcode", "csnameifcode", "fontcharifcode", "fontslantperpoint", "fontinterwordspace", "fontinterwordstretch", "fontinterwordshrink", "fontexheight", "fontemwidth", "fontextraspace", "slantperpoint", "interwordspace", "interwordstretch", "interwordshrink", "exheight", "emwidth", "extraspace", "mathsupdisplay", "mathsupnormal", "mathsupcramped", "mathsubnormal", "mathsubcombined", "mathaxisheight", "startmode", "stopmode", "startnotmode", "stopnotmode", "startmodeset", "stopmodeset", "doifmode", "doifmodeelse", "doifnotmode", "startmodeset", "stopmodeset", "startallmodes", "stopallmodes", "startnotallmodes", "stopnotallmodes", "doifallmodes", "doifallmodeselse", "doifnotallmodes", "startenvironment", "stopenvironment", "environment", "startcomponent", "stopcomponent", "component", "startproduct", "stopproduct", "product", "startproject", "stopproject", "project", "starttext", "stoptext", "startnotext", "stopnotext", "startdocument", "stopdocument", "documentvariable", "setupdocument", "startmodule", "stopmodule", "usemodule", "usetexmodule", "useluamodule", "setupmodule", "currentmoduleparameter", "moduleparameter", "everystarttext", "startTEXpage", "stopTEXpage", "enablemode", "disablemode", "preventmode", "definemode", "globalenablemode", "globaldisablemode", "globalpreventmode", "pushmode", "popmode", "typescriptone", "typescripttwo", "typescriptthree", "mathsizesuffix", "mathordcode", "mathopcode", "mathbincode", "mathrelcode", "mathopencode", "mathclosecode", "mathpunctcode", "mathalphacode", "mathinnercode", "mathnothingcode", "mathlimopcode", "mathnolopcode", "mathboxcode", "mathchoicecode", "mathaccentcode", "mathradicalcode", "constantnumber", "constantnumberargument", "constantdimen", "constantdimenargument", "constantemptyargument", "continueifinputfile", "luastringsep", "!!bs", "!!es", "lefttorightmark", "righttoleftmark", "breakablethinspace", "nobreakspace", "nonbreakablespace", "narrownobreakspace", "zerowidthnobreakspace", "ideographicspace", "ideographichalffillspace", "twoperemspace", "threeperemspace", "fourperemspace", "fiveperemspace", "sixperemspace", "figurespace", "punctuationspace", "hairspace", "zerowidthspace", "zerowidthnonjoiner", "zerowidthjoiner", "zwnj", "zwj", "optionalspace", "asciispacechar" }, - ["helpers"]={ "startsetups", "stopsetups", "startxmlsetups", "stopxmlsetups", "startluasetups", "stopluasetups", "starttexsetups", "stoptexsetups", "startrawsetups", "stoprawsetups", "startlocalsetups", "stoplocalsetups", "starttexdefinition", "stoptexdefinition", "starttexcode", "stoptexcode", "startcontextcode", "stopcontextcode", "startcontextdefinitioncode", "stopcontextdefinitioncode", "texdefinition", "doifsetupselse", "doifsetups", "doifnotsetups", "setup", "setups", "texsetup", "xmlsetup", "luasetup", "directsetup", "doifelsecommandhandler", "doifnotcommandhandler", "doifcommandhandler", "newmode", "setmode", "resetmode", "newsystemmode", "setsystemmode", "resetsystemmode", "pushsystemmode", "popsystemmode", "booleanmodevalue", "newcount", "newdimen", "newskip", "newmuskip", "newbox", "newtoks", "newread", "newwrite", "newmarks", "newinsert", "newattribute", "newif", "newlanguage", "newfamily", "newfam", "newhelp", "then", "begcsname", "strippedcsname", "firstargumentfalse", "firstargumenttrue", "secondargumentfalse", "secondargumenttrue", "thirdargumentfalse", "thirdargumenttrue", "fourthargumentfalse", "fourthargumenttrue", "fifthargumentfalse", "fifthsargumenttrue", "sixthargumentfalse", "sixtsargumenttrue", "doglobal", "dodoglobal", "redoglobal", "resetglobal", "donothing", "dontcomplain", "forgetall", "donetrue", "donefalse", "htdp", "unvoidbox", "hfilll", "vfilll", "mathbox", "mathlimop", "mathnolop", "mathnothing", "mathalpha", "currentcatcodetable", "defaultcatcodetable", "catcodetablename", "newcatcodetable", "startcatcodetable", "stopcatcodetable", "startextendcatcodetable", "stopextendcatcodetable", "pushcatcodetable", "popcatcodetable", "restorecatcodes", "setcatcodetable", "letcatcodecommand", "defcatcodecommand", "uedcatcodecommand", "hglue", "vglue", "hfillneg", "vfillneg", "hfilllneg", "vfilllneg", "ruledhss", "ruledhfil", "ruledhfill", "ruledhfilneg", "ruledhfillneg", "normalhfillneg", "ruledvss", "ruledvfil", "ruledvfill", "ruledvfilneg", "ruledvfillneg", "normalvfillneg", "ruledhbox", "ruledvbox", "ruledvtop", "ruledvcenter", "ruledmbox", "ruledhskip", "ruledvskip", "ruledkern", "ruledmskip", "ruledmkern", "ruledhglue", "ruledvglue", "normalhglue", "normalvglue", "ruledpenalty", "filledhboxb", "filledhboxr", "filledhboxg", "filledhboxc", "filledhboxm", "filledhboxy", "filledhboxk", "scratchcounter", "globalscratchcounter", "scratchdimen", "globalscratchdimen", "scratchskip", "globalscratchskip", "scratchmuskip", "globalscratchmuskip", "scratchtoks", "globalscratchtoks", "scratchbox", "globalscratchbox", "normalbaselineskip", "normallineskip", "normallineskiplimit", "availablehsize", "localhsize", "setlocalhsize", "nextbox", "dowithnextbox", "dowithnextboxcs", "dowithnextboxcontent", "dowithnextboxcontentcs", "scratchwidth", "scratchheight", "scratchdepth", "scratchoffset", "scratchdistance", "scratchhsize", "scratchvsize", "scratchxoffset", "scratchyoffset", "scratchhoffset", "scratchvoffset", "scratchxposition", "scratchyposition", "scratchtopoffset", "scratchbottomoffset", "scratchleftoffset", "scratchrightoffset", "scratchcounterone", "scratchcountertwo", "scratchcounterthree", "scratchdimenone", "scratchdimentwo", "scratchdimenthree", "scratchskipone", "scratchskiptwo", "scratchskipthree", "scratchmuskipone", "scratchmuskiptwo", "scratchmuskipthree", "scratchtoksone", "scratchtokstwo", "scratchtoksthree", "scratchboxone", "scratchboxtwo", "scratchboxthree", "scratchnx", "scratchny", "scratchmx", "scratchmy", "scratchunicode", "scratchleftskip", "scratchrightskip", "scratchtopskip", "scratchbottomskip", "doif", "doifnot", "doifelse", "doifinset", "doifnotinset", "doifinsetelse", "doifnextcharelse", "doifnextoptionalelse", "doifnextoptionalcselse", "doiffastoptionalcheckelse", "doifnextbgroupelse", "doifnextbgroupcselse", "doifnextparenthesiselse", "doifundefinedelse", "doifdefinedelse", "doifundefined", "doifdefined", "doifelsevalue", "doifvalue", "doifnotvalue", "doifnothing", "doifsomething", "doifelsenothing", "doifsomethingelse", "doifvaluenothing", "doifvaluesomething", "doifelsevaluenothing", "doifdimensionelse", "doifnumberelse", "doifnumber", "doifnotnumber", "doifcommonelse", "doifcommon", "doifnotcommon", "doifinstring", "doifnotinstring", "doifinstringelse", "doifassignmentelse", "docheckassignment", "tracingall", "tracingnone", "loggingall", "removetoks", "appendtoks", "prependtoks", "appendtotoks", "prependtotoks", "to", "endgraf", "endpar", "everyendpar", "reseteverypar", "finishpar", "empty", "null", "space", "quad", "enspace", "nbsp", "obeyspaces", "obeylines", "obeyedspace", "obeyedline", "obeyedtab", "obeyedpage", "normalspace", "executeifdefined", "singleexpandafter", "doubleexpandafter", "tripleexpandafter", "dontleavehmode", "removelastspace", "removeunwantedspaces", "keepunwantedspaces", "wait", "writestatus", "define", "defineexpandable", "redefine", "setmeasure", "setemeasure", "setgmeasure", "setxmeasure", "definemeasure", "freezemeasure", "measure", "measured", "installcorenamespace", "getvalue", "getuvalue", "setvalue", "setevalue", "setgvalue", "setxvalue", "letvalue", "letgvalue", "resetvalue", "undefinevalue", "ignorevalue", "setuvalue", "setuevalue", "setugvalue", "setuxvalue", "globallet", "glet", "udef", "ugdef", "uedef", "uxdef", "checked", "unique", "getparameters", "geteparameters", "getgparameters", "getxparameters", "forgetparameters", "copyparameters", "getdummyparameters", "dummyparameter", "directdummyparameter", "setdummyparameter", "letdummyparameter", "usedummystyleandcolor", "usedummystyleparameter", "usedummycolorparameter", "processcommalist", "processcommacommand", "quitcommalist", "quitprevcommalist", "processaction", "processallactions", "processfirstactioninset", "processallactionsinset", "unexpanded", "expanded", "startexpanded", "stopexpanded", "protected", "protect", "unprotect", "firstofoneargument", "firstoftwoarguments", "secondoftwoarguments", "firstofthreearguments", "secondofthreearguments", "thirdofthreearguments", "firstoffourarguments", "secondoffourarguments", "thirdoffourarguments", "fourthoffourarguments", "firstoffivearguments", "secondoffivearguments", "thirdoffivearguments", "fourthoffivearguments", "fifthoffivearguments", "firstofsixarguments", "secondofsixarguments", "thirdofsixarguments", "fourthofsixarguments", "fifthofsixarguments", "sixthofsixarguments", "firstofoneunexpanded", "gobbleoneargument", "gobbletwoarguments", "gobblethreearguments", "gobblefourarguments", "gobblefivearguments", "gobblesixarguments", "gobblesevenarguments", "gobbleeightarguments", "gobbleninearguments", "gobbletenarguments", "gobbleoneoptional", "gobbletwooptionals", "gobblethreeoptionals", "gobblefouroptionals", "gobblefiveoptionals", "dorecurse", "doloop", "exitloop", "dostepwiserecurse", "recurselevel", "recursedepth", "dofastloopcs", "dowith", "newconstant", "setnewconstant", "setconstant", "setconstantvalue", "newconditional", "settrue", "setfalse", "settruevalue", "setfalsevalue", "newmacro", "setnewmacro", "newfraction", "newsignal", "dosingleempty", "dodoubleempty", "dotripleempty", "doquadrupleempty", "doquintupleempty", "dosixtupleempty", "doseventupleempty", "dosingleargument", "dodoubleargument", "dotripleargument", "doquadrupleargument", "doquintupleargument", "dosixtupleargument", "doseventupleargument", "dosinglegroupempty", "dodoublegroupempty", "dotriplegroupempty", "doquadruplegroupempty", "doquintuplegroupempty", "permitspacesbetweengroups", "dontpermitspacesbetweengroups", "nopdfcompression", "maximumpdfcompression", "normalpdfcompression", "modulonumber", "dividenumber", "getfirstcharacter", "doiffirstcharelse", "startnointerference", "stopnointerference", "twodigits", "threedigits", "leftorright", "offinterlineskip", "oninterlineskip", "nointerlineskip", "strut", "setstrut", "strutbox", "strutht", "strutdp", "strutwd", "struthtdp", "begstrut", "endstrut", "lineheight", "ordordspacing", "ordopspacing", "ordbinspacing", "ordrelspacing", "ordopenspacing", "ordclosespacing", "ordpunctspacing", "ordinnerspacing", "opordspacing", "opopspacing", "opbinspacing", "oprelspacing", "opopenspacing", "opclosespacing", "oppunctspacing", "opinnerspacing", "binordspacing", "binopspacing", "binbinspacing", "binrelspacing", "binopenspacing", "binclosespacing", "binpunctspacing", "bininnerspacing", "relordspacing", "relopspacing", "relbinspacing", "relrelspacing", "relopenspacing", "relclosespacing", "relpunctspacing", "relinnerspacing", "openordspacing", "openopspacing", "openbinspacing", "openrelspacing", "openopenspacing", "openclosespacing", "openpunctspacing", "openinnerspacing", "closeordspacing", "closeopspacing", "closebinspacing", "closerelspacing", "closeopenspacing", "closeclosespacing", "closepunctspacing", "closeinnerspacing", "punctordspacing", "punctopspacing", "punctbinspacing", "punctrelspacing", "punctopenspacing", "punctclosespacing", "punctpunctspacing", "punctinnerspacing", "innerordspacing", "inneropspacing", "innerbinspacing", "innerrelspacing", "inneropenspacing", "innerclosespacing", "innerpunctspacing", "innerinnerspacing", "normalreqno", "startimath", "stopimath", "normalstartimath", "normalstopimath", "startdmath", "stopdmath", "normalstartdmath", "normalstopdmath", "uncramped", "cramped", "triggermathstyle", "mathstylefont", "mathsmallstylefont", "mathstyleface", "mathsmallstyleface", "mathstylecommand", "mathpalette", "mathstylehbox", "mathstylevbox", "mathstylevcenter", "mathstylevcenteredhbox", "mathstylevcenteredvbox", "mathtext", "setmathsmalltextbox", "setmathtextbox", "triggerdisplaystyle", "triggertextstyle", "triggerscriptstyle", "triggerscriptscriptstyle", "triggeruncrampedstyle", "triggercrampedstyle", "triggersmallstyle", "triggeruncrampedsmallstyle", "triggercrampedsmallstyle", "triggerbigstyle", "triggeruncrampedbigstyle", "triggercrampedbigstyle", "luaexpr", "expdoifelse", "expdoif", "expdoifnot", "expdoifcommonelse", "expdoifinsetelse", "ctxdirectlua", "ctxlatelua", "ctxsprint", "ctxwrite", "ctxcommand", "ctxdirectcommand", "ctxlatecommand", "ctxreport", "ctxlua", "luacode", "lateluacode", "directluacode", "registerctxluafile", "ctxloadluafile", "luaversion", "luamajorversion", "luaminorversion", "ctxluacode", "luaconditional", "luaexpanded", "startluaparameterset", "stopluaparameterset", "luaparameterset", "definenamedlua", "obeylualines", "obeyluatokens", "startluacode", "stopluacode", "startlua", "stoplua", "startctxfunction", "stopctxfunction", "ctxfunction", "startctxfunctiondefinition", "stopctxfunctiondefinition", "carryoverpar", "assumelongusagecs", "Umathbotaccent", "righttolefthbox", "lefttorighthbox", "righttoleftvbox", "lefttorightvbox", "righttoleftvtop", "lefttorightvtop", "rtlhbox", "ltrhbox", "rtlvbox", "ltrvbox", "rtlvtop", "ltrvtop", "autodirhbox", "autodirvbox", "autodirvtop", "lefttoright", "righttoleft", "synchronizelayoutdirection", "synchronizedisplaydirection", "synchronizeinlinedirection", "lesshyphens", "morehyphens", "nohyphens", "dohyphens", "Ucheckedstartdisplaymath", "Ucheckedstopdisplaymath" }, + ["helpers"]={ "startsetups", "stopsetups", "startxmlsetups", "stopxmlsetups", "startluasetups", "stopluasetups", "starttexsetups", "stoptexsetups", "startrawsetups", "stoprawsetups", "startlocalsetups", "stoplocalsetups", "starttexdefinition", "stoptexdefinition", "starttexcode", "stoptexcode", "startcontextcode", "stopcontextcode", "startcontextdefinitioncode", "stopcontextdefinitioncode", "texdefinition", "doifsetupselse", "doifsetups", "doifnotsetups", "setup", "setups", "texsetup", "xmlsetup", "luasetup", "directsetup", "fastsetup", "doifelsecommandhandler", "doifnotcommandhandler", "doifcommandhandler", "newmode", "setmode", "resetmode", "newsystemmode", "setsystemmode", "resetsystemmode", "pushsystemmode", "popsystemmode", "booleanmodevalue", "newcount", "newdimen", "newskip", "newmuskip", "newbox", "newtoks", "newread", "newwrite", "newmarks", "newinsert", "newattribute", "newif", "newlanguage", "newfamily", "newfam", "newhelp", "then", "begcsname", "strippedcsname", "firstargumentfalse", "firstargumenttrue", "secondargumentfalse", "secondargumenttrue", "thirdargumentfalse", "thirdargumenttrue", "fourthargumentfalse", "fourthargumenttrue", "fifthargumentfalse", "fifthsargumenttrue", "sixthargumentfalse", "sixtsargumenttrue", "doglobal", "dodoglobal", "redoglobal", "resetglobal", "donothing", "dontcomplain", "forgetall", "donetrue", "donefalse", "htdp", "unvoidbox", "hfilll", "vfilll", "mathbox", "mathlimop", "mathnolop", "mathnothing", "mathalpha", "currentcatcodetable", "defaultcatcodetable", "catcodetablename", "newcatcodetable", "startcatcodetable", "stopcatcodetable", "startextendcatcodetable", "stopextendcatcodetable", "pushcatcodetable", "popcatcodetable", "restorecatcodes", "setcatcodetable", "letcatcodecommand", "defcatcodecommand", "uedcatcodecommand", "hglue", "vglue", "hfillneg", "vfillneg", "hfilllneg", "vfilllneg", "ruledhss", "ruledhfil", "ruledhfill", "ruledhfilneg", "ruledhfillneg", "normalhfillneg", "ruledvss", "ruledvfil", "ruledvfill", "ruledvfilneg", "ruledvfillneg", "normalvfillneg", "ruledhbox", "ruledvbox", "ruledvtop", "ruledvcenter", "ruledmbox", "ruledhskip", "ruledvskip", "ruledkern", "ruledmskip", "ruledmkern", "ruledhglue", "ruledvglue", "normalhglue", "normalvglue", "ruledpenalty", "filledhboxb", "filledhboxr", "filledhboxg", "filledhboxc", "filledhboxm", "filledhboxy", "filledhboxk", "scratchcounter", "globalscratchcounter", "scratchdimen", "globalscratchdimen", "scratchskip", "globalscratchskip", "scratchmuskip", "globalscratchmuskip", "scratchtoks", "globalscratchtoks", "scratchbox", "globalscratchbox", "normalbaselineskip", "normallineskip", "normallineskiplimit", "availablehsize", "localhsize", "setlocalhsize", "nextbox", "dowithnextbox", "dowithnextboxcs", "dowithnextboxcontent", "dowithnextboxcontentcs", "scratchwidth", "scratchheight", "scratchdepth", "scratchoffset", "scratchdistance", "scratchhsize", "scratchvsize", "scratchxoffset", "scratchyoffset", "scratchhoffset", "scratchvoffset", "scratchxposition", "scratchyposition", "scratchtopoffset", "scratchbottomoffset", "scratchleftoffset", "scratchrightoffset", "scratchcounterone", "scratchcountertwo", "scratchcounterthree", "scratchdimenone", "scratchdimentwo", "scratchdimenthree", "scratchskipone", "scratchskiptwo", "scratchskipthree", "scratchmuskipone", "scratchmuskiptwo", "scratchmuskipthree", "scratchtoksone", "scratchtokstwo", "scratchtoksthree", "scratchboxone", "scratchboxtwo", "scratchboxthree", "scratchnx", "scratchny", "scratchmx", "scratchmy", "scratchunicode", "scratchleftskip", "scratchrightskip", "scratchtopskip", "scratchbottomskip", "doif", "doifnot", "doifelse", "doifinset", "doifnotinset", "doifinsetelse", "doifnextcharelse", "doifnextoptionalelse", "doifnextoptionalcselse", "doiffastoptionalcheckelse", "doifnextbgroupelse", "doifnextbgroupcselse", "doifnextparenthesiselse", "doifundefinedelse", "doifdefinedelse", "doifundefined", "doifdefined", "doifelsevalue", "doifvalue", "doifnotvalue", "doifnothing", "doifsomething", "doifelsenothing", "doifsomethingelse", "doifvaluenothing", "doifvaluesomething", "doifelsevaluenothing", "doifdimensionelse", "doifnumberelse", "doifnumber", "doifnotnumber", "doifcommonelse", "doifcommon", "doifnotcommon", "doifinstring", "doifnotinstring", "doifinstringelse", "doifassignmentelse", "docheckassignment", "tracingall", "tracingnone", "loggingall", "removetoks", "appendtoks", "prependtoks", "appendtotoks", "prependtotoks", "to", "endgraf", "endpar", "everyendpar", "reseteverypar", "finishpar", "empty", "null", "space", "quad", "enspace", "nbsp", "obeyspaces", "obeylines", "obeyedspace", "obeyedline", "obeyedtab", "obeyedpage", "normalspace", "executeifdefined", "singleexpandafter", "doubleexpandafter", "tripleexpandafter", "dontleavehmode", "removelastspace", "removeunwantedspaces", "keepunwantedspaces", "wait", "writestatus", "define", "defineexpandable", "redefine", "setmeasure", "setemeasure", "setgmeasure", "setxmeasure", "definemeasure", "freezemeasure", "measure", "measured", "installcorenamespace", "getvalue", "getuvalue", "setvalue", "setevalue", "setgvalue", "setxvalue", "letvalue", "letgvalue", "resetvalue", "undefinevalue", "ignorevalue", "setuvalue", "setuevalue", "setugvalue", "setuxvalue", "globallet", "glet", "udef", "ugdef", "uedef", "uxdef", "checked", "unique", "getparameters", "geteparameters", "getgparameters", "getxparameters", "forgetparameters", "copyparameters", "getdummyparameters", "dummyparameter", "directdummyparameter", "setdummyparameter", "letdummyparameter", "usedummystyleandcolor", "usedummystyleparameter", "usedummycolorparameter", "processcommalist", "processcommacommand", "quitcommalist", "quitprevcommalist", "processaction", "processallactions", "processfirstactioninset", "processallactionsinset", "unexpanded", "expanded", "startexpanded", "stopexpanded", "protected", "protect", "unprotect", "firstofoneargument", "firstoftwoarguments", "secondoftwoarguments", "firstofthreearguments", "secondofthreearguments", "thirdofthreearguments", "firstoffourarguments", "secondoffourarguments", "thirdoffourarguments", "fourthoffourarguments", "firstoffivearguments", "secondoffivearguments", "thirdoffivearguments", "fourthoffivearguments", "fifthoffivearguments", "firstofsixarguments", "secondofsixarguments", "thirdofsixarguments", "fourthofsixarguments", "fifthofsixarguments", "sixthofsixarguments", "firstofoneunexpanded", "gobbleoneargument", "gobbletwoarguments", "gobblethreearguments", "gobblefourarguments", "gobblefivearguments", "gobblesixarguments", "gobblesevenarguments", "gobbleeightarguments", "gobbleninearguments", "gobbletenarguments", "gobbleoneoptional", "gobbletwooptionals", "gobblethreeoptionals", "gobblefouroptionals", "gobblefiveoptionals", "dorecurse", "doloop", "exitloop", "dostepwiserecurse", "recurselevel", "recursedepth", "dofastloopcs", "dowith", "newconstant", "setnewconstant", "setconstant", "setconstantvalue", "newconditional", "settrue", "setfalse", "settruevalue", "setfalsevalue", "newmacro", "setnewmacro", "newfraction", "newsignal", "dosingleempty", "dodoubleempty", "dotripleempty", "doquadrupleempty", "doquintupleempty", "dosixtupleempty", "doseventupleempty", "dosingleargument", "dodoubleargument", "dotripleargument", "doquadrupleargument", "doquintupleargument", "dosixtupleargument", "doseventupleargument", "dosinglegroupempty", "dodoublegroupempty", "dotriplegroupempty", "doquadruplegroupempty", "doquintuplegroupempty", "permitspacesbetweengroups", "dontpermitspacesbetweengroups", "nopdfcompression", "maximumpdfcompression", "normalpdfcompression", "modulonumber", "dividenumber", "getfirstcharacter", "doiffirstcharelse", "startnointerference", "stopnointerference", "twodigits", "threedigits", "leftorright", "offinterlineskip", "oninterlineskip", "nointerlineskip", "strut", "setstrut", "strutbox", "strutht", "strutdp", "strutwd", "struthtdp", "begstrut", "endstrut", "lineheight", "ordordspacing", "ordopspacing", "ordbinspacing", "ordrelspacing", "ordopenspacing", "ordclosespacing", "ordpunctspacing", "ordinnerspacing", "opordspacing", "opopspacing", "opbinspacing", "oprelspacing", "opopenspacing", "opclosespacing", "oppunctspacing", "opinnerspacing", "binordspacing", "binopspacing", "binbinspacing", "binrelspacing", "binopenspacing", "binclosespacing", "binpunctspacing", "bininnerspacing", "relordspacing", "relopspacing", "relbinspacing", "relrelspacing", "relopenspacing", "relclosespacing", "relpunctspacing", "relinnerspacing", "openordspacing", "openopspacing", "openbinspacing", "openrelspacing", "openopenspacing", "openclosespacing", "openpunctspacing", "openinnerspacing", "closeordspacing", "closeopspacing", "closebinspacing", "closerelspacing", "closeopenspacing", "closeclosespacing", "closepunctspacing", "closeinnerspacing", "punctordspacing", "punctopspacing", "punctbinspacing", "punctrelspacing", "punctopenspacing", "punctclosespacing", "punctpunctspacing", "punctinnerspacing", "innerordspacing", "inneropspacing", "innerbinspacing", "innerrelspacing", "inneropenspacing", "innerclosespacing", "innerpunctspacing", "innerinnerspacing", "normalreqno", "startimath", "stopimath", "normalstartimath", "normalstopimath", "startdmath", "stopdmath", "normalstartdmath", "normalstopdmath", "uncramped", "cramped", "triggermathstyle", "mathstylefont", "mathsmallstylefont", "mathstyleface", "mathsmallstyleface", "mathstylecommand", "mathpalette", "mathstylehbox", "mathstylevbox", "mathstylevcenter", "mathstylevcenteredhbox", "mathstylevcenteredvbox", "mathtext", "setmathsmalltextbox", "setmathtextbox", "triggerdisplaystyle", "triggertextstyle", "triggerscriptstyle", "triggerscriptscriptstyle", "triggeruncrampedstyle", "triggercrampedstyle", "triggersmallstyle", "triggeruncrampedsmallstyle", "triggercrampedsmallstyle", "triggerbigstyle", "triggeruncrampedbigstyle", "triggercrampedbigstyle", "luaexpr", "expdoifelse", "expdoif", "expdoifnot", "expdoifcommonelse", "expdoifinsetelse", "ctxdirectlua", "ctxlatelua", "ctxsprint", "ctxwrite", "ctxcommand", "ctxdirectcommand", "ctxlatecommand", "ctxreport", "ctxlua", "luacode", "lateluacode", "directluacode", "registerctxluafile", "ctxloadluafile", "luaversion", "luamajorversion", "luaminorversion", "ctxluacode", "luaconditional", "luaexpanded", "startluaparameterset", "stopluaparameterset", "luaparameterset", "definenamedlua", "obeylualines", "obeyluatokens", "startluacode", "stopluacode", "startlua", "stoplua", "startctxfunction", "stopctxfunction", "ctxfunction", "startctxfunctiondefinition", "stopctxfunctiondefinition", "carryoverpar", "assumelongusagecs", "Umathbotaccent", "righttolefthbox", "lefttorighthbox", "righttoleftvbox", "lefttorightvbox", "righttoleftvtop", "lefttorightvtop", "rtlhbox", "ltrhbox", "rtlvbox", "ltrvbox", "rtlvtop", "ltrvtop", "autodirhbox", "autodirvbox", "autodirvtop", "lefttoright", "righttoleft", "synchronizelayoutdirection", "synchronizedisplaydirection", "synchronizeinlinedirection", "lesshyphens", "morehyphens", "nohyphens", "dohyphens", "Ucheckedstartdisplaymath", "Ucheckedstopdisplaymath" }, }
\ No newline at end of file diff --git a/context/data/scite/context/scite-context-data-context.properties b/context/data/scite/context/scite-context-data-context.properties index c454583fa..7ef113dc8 100644 --- a/context/data/scite/context/scite-context-data-context.properties +++ b/context/data/scite/context/scite-context-data-context.properties @@ -72,124 +72,125 @@ stoprawsetups startlocalsetups stoplocalsetups starttexdefinition stoptexdefinit starttexcode stoptexcode startcontextcode stopcontextcode startcontextdefinitioncode \ stopcontextdefinitioncode texdefinition doifsetupselse doifsetups doifnotsetups \ setup setups texsetup xmlsetup luasetup \ -directsetup doifelsecommandhandler doifnotcommandhandler doifcommandhandler newmode \ -setmode resetmode newsystemmode setsystemmode resetsystemmode \ -pushsystemmode popsystemmode booleanmodevalue newcount newdimen \ -newskip newmuskip newbox newtoks newread \ -newwrite newmarks newinsert newattribute newif \ -newlanguage newfamily newfam newhelp then \ -begcsname strippedcsname firstargumentfalse firstargumenttrue secondargumentfalse \ -secondargumenttrue thirdargumentfalse thirdargumenttrue fourthargumentfalse fourthargumenttrue \ -fifthargumentfalse fifthsargumenttrue sixthargumentfalse sixtsargumenttrue doglobal \ -dodoglobal redoglobal resetglobal donothing dontcomplain \ -forgetall donetrue donefalse htdp unvoidbox \ -hfilll vfilll mathbox mathlimop mathnolop \ -mathnothing mathalpha currentcatcodetable defaultcatcodetable catcodetablename \ -newcatcodetable startcatcodetable stopcatcodetable startextendcatcodetable stopextendcatcodetable \ -pushcatcodetable popcatcodetable restorecatcodes setcatcodetable letcatcodecommand \ -defcatcodecommand uedcatcodecommand hglue vglue hfillneg \ -vfillneg hfilllneg vfilllneg ruledhss ruledhfil \ -ruledhfill ruledhfilneg ruledhfillneg normalhfillneg ruledvss \ -ruledvfil ruledvfill ruledvfilneg ruledvfillneg normalvfillneg \ -ruledhbox ruledvbox ruledvtop ruledvcenter ruledmbox \ -ruledhskip ruledvskip ruledkern ruledmskip ruledmkern \ -ruledhglue ruledvglue normalhglue normalvglue ruledpenalty \ -filledhboxb filledhboxr filledhboxg filledhboxc filledhboxm \ -filledhboxy filledhboxk scratchcounter globalscratchcounter scratchdimen \ -globalscratchdimen scratchskip globalscratchskip scratchmuskip globalscratchmuskip \ -scratchtoks globalscratchtoks scratchbox globalscratchbox normalbaselineskip \ -normallineskip normallineskiplimit availablehsize localhsize setlocalhsize \ -nextbox dowithnextbox dowithnextboxcs dowithnextboxcontent dowithnextboxcontentcs \ -scratchwidth scratchheight scratchdepth scratchoffset scratchdistance \ -scratchhsize scratchvsize scratchxoffset scratchyoffset scratchhoffset \ -scratchvoffset scratchxposition scratchyposition scratchtopoffset scratchbottomoffset \ -scratchleftoffset scratchrightoffset scratchcounterone scratchcountertwo scratchcounterthree \ -scratchdimenone scratchdimentwo scratchdimenthree scratchskipone scratchskiptwo \ -scratchskipthree scratchmuskipone scratchmuskiptwo scratchmuskipthree scratchtoksone \ -scratchtokstwo scratchtoksthree scratchboxone scratchboxtwo scratchboxthree \ -scratchnx scratchny scratchmx scratchmy scratchunicode \ -scratchleftskip scratchrightskip scratchtopskip scratchbottomskip doif \ -doifnot doifelse doifinset doifnotinset doifinsetelse \ -doifnextcharelse doifnextoptionalelse doifnextoptionalcselse doiffastoptionalcheckelse doifnextbgroupelse \ -doifnextbgroupcselse doifnextparenthesiselse doifundefinedelse doifdefinedelse doifundefined \ -doifdefined doifelsevalue doifvalue doifnotvalue doifnothing \ -doifsomething doifelsenothing doifsomethingelse doifvaluenothing doifvaluesomething \ -doifelsevaluenothing doifdimensionelse doifnumberelse doifnumber doifnotnumber \ -doifcommonelse doifcommon doifnotcommon doifinstring doifnotinstring \ -doifinstringelse doifassignmentelse docheckassignment tracingall tracingnone \ -loggingall removetoks appendtoks prependtoks appendtotoks \ -prependtotoks to endgraf endpar everyendpar \ -reseteverypar finishpar empty null space \ -quad enspace nbsp obeyspaces obeylines \ -obeyedspace obeyedline obeyedtab obeyedpage normalspace \ -executeifdefined singleexpandafter doubleexpandafter tripleexpandafter dontleavehmode \ -removelastspace removeunwantedspaces keepunwantedspaces wait writestatus \ -define defineexpandable redefine setmeasure setemeasure \ -setgmeasure setxmeasure definemeasure freezemeasure measure \ -measured installcorenamespace getvalue getuvalue setvalue \ -setevalue setgvalue setxvalue letvalue letgvalue \ -resetvalue undefinevalue ignorevalue setuvalue setuevalue \ -setugvalue setuxvalue globallet glet udef \ -ugdef uedef uxdef checked unique \ -getparameters geteparameters getgparameters getxparameters forgetparameters \ -copyparameters getdummyparameters dummyparameter directdummyparameter setdummyparameter \ -letdummyparameter usedummystyleandcolor usedummystyleparameter usedummycolorparameter processcommalist \ -processcommacommand quitcommalist quitprevcommalist processaction processallactions \ -processfirstactioninset processallactionsinset unexpanded expanded startexpanded \ -stopexpanded protected protect unprotect firstofoneargument \ -firstoftwoarguments secondoftwoarguments firstofthreearguments secondofthreearguments thirdofthreearguments \ -firstoffourarguments secondoffourarguments thirdoffourarguments fourthoffourarguments firstoffivearguments \ -secondoffivearguments thirdoffivearguments fourthoffivearguments fifthoffivearguments firstofsixarguments \ -secondofsixarguments thirdofsixarguments fourthofsixarguments fifthofsixarguments sixthofsixarguments \ -firstofoneunexpanded gobbleoneargument gobbletwoarguments gobblethreearguments gobblefourarguments \ -gobblefivearguments gobblesixarguments gobblesevenarguments gobbleeightarguments gobbleninearguments \ -gobbletenarguments gobbleoneoptional gobbletwooptionals gobblethreeoptionals gobblefouroptionals \ -gobblefiveoptionals dorecurse doloop exitloop dostepwiserecurse \ -recurselevel recursedepth dofastloopcs dowith newconstant \ -setnewconstant setconstant setconstantvalue newconditional settrue \ -setfalse settruevalue setfalsevalue newmacro setnewmacro \ -newfraction newsignal dosingleempty dodoubleempty dotripleempty \ -doquadrupleempty doquintupleempty dosixtupleempty doseventupleempty dosingleargument \ -dodoubleargument dotripleargument doquadrupleargument doquintupleargument dosixtupleargument \ -doseventupleargument dosinglegroupempty dodoublegroupempty dotriplegroupempty doquadruplegroupempty \ -doquintuplegroupempty permitspacesbetweengroups dontpermitspacesbetweengroups nopdfcompression maximumpdfcompression \ -normalpdfcompression modulonumber dividenumber getfirstcharacter doiffirstcharelse \ -startnointerference stopnointerference twodigits threedigits leftorright \ -offinterlineskip oninterlineskip nointerlineskip strut setstrut \ -strutbox strutht strutdp strutwd struthtdp \ -begstrut endstrut lineheight ordordspacing ordopspacing \ -ordbinspacing ordrelspacing ordopenspacing ordclosespacing ordpunctspacing \ -ordinnerspacing opordspacing opopspacing opbinspacing oprelspacing \ -opopenspacing opclosespacing oppunctspacing opinnerspacing binordspacing \ -binopspacing binbinspacing binrelspacing binopenspacing binclosespacing \ -binpunctspacing bininnerspacing relordspacing relopspacing relbinspacing \ -relrelspacing relopenspacing relclosespacing relpunctspacing relinnerspacing \ -openordspacing openopspacing openbinspacing openrelspacing openopenspacing \ -openclosespacing openpunctspacing openinnerspacing closeordspacing closeopspacing \ -closebinspacing closerelspacing closeopenspacing closeclosespacing closepunctspacing \ -closeinnerspacing punctordspacing punctopspacing punctbinspacing punctrelspacing \ -punctopenspacing punctclosespacing punctpunctspacing punctinnerspacing innerordspacing \ -inneropspacing innerbinspacing innerrelspacing inneropenspacing innerclosespacing \ -innerpunctspacing innerinnerspacing normalreqno startimath stopimath \ -normalstartimath normalstopimath startdmath stopdmath normalstartdmath \ -normalstopdmath uncramped cramped triggermathstyle mathstylefont \ -mathsmallstylefont mathstyleface mathsmallstyleface mathstylecommand mathpalette \ -mathstylehbox mathstylevbox mathstylevcenter mathstylevcenteredhbox mathstylevcenteredvbox \ -mathtext setmathsmalltextbox setmathtextbox triggerdisplaystyle triggertextstyle \ -triggerscriptstyle triggerscriptscriptstyle triggeruncrampedstyle triggercrampedstyle triggersmallstyle \ -triggeruncrampedsmallstyle triggercrampedsmallstyle triggerbigstyle triggeruncrampedbigstyle triggercrampedbigstyle \ -luaexpr expdoifelse expdoif expdoifnot expdoifcommonelse \ -expdoifinsetelse ctxdirectlua ctxlatelua ctxsprint ctxwrite \ -ctxcommand ctxdirectcommand ctxlatecommand ctxreport ctxlua \ -luacode lateluacode directluacode registerctxluafile ctxloadluafile \ -luaversion luamajorversion luaminorversion ctxluacode luaconditional \ -luaexpanded startluaparameterset stopluaparameterset luaparameterset definenamedlua \ -obeylualines obeyluatokens startluacode stopluacode startlua \ -stoplua startctxfunction stopctxfunction ctxfunction startctxfunctiondefinition \ -stopctxfunctiondefinition carryoverpar assumelongusagecs Umathbotaccent righttolefthbox \ -lefttorighthbox righttoleftvbox lefttorightvbox righttoleftvtop lefttorightvtop \ -rtlhbox ltrhbox rtlvbox ltrvbox rtlvtop \ -ltrvtop autodirhbox autodirvbox autodirvtop lefttoright \ -righttoleft synchronizelayoutdirection synchronizedisplaydirection synchronizeinlinedirection lesshyphens \ -morehyphens nohyphens dohyphens Ucheckedstartdisplaymath Ucheckedstopdisplaymath +directsetup fastsetup doifelsecommandhandler doifnotcommandhandler doifcommandhandler \ +newmode setmode resetmode newsystemmode setsystemmode \ +resetsystemmode pushsystemmode popsystemmode booleanmodevalue newcount \ +newdimen newskip newmuskip newbox newtoks \ +newread newwrite newmarks newinsert newattribute \ +newif newlanguage newfamily newfam newhelp \ +then begcsname strippedcsname firstargumentfalse firstargumenttrue \ +secondargumentfalse secondargumenttrue thirdargumentfalse thirdargumenttrue fourthargumentfalse \ +fourthargumenttrue fifthargumentfalse fifthsargumenttrue sixthargumentfalse sixtsargumenttrue \ +doglobal dodoglobal redoglobal resetglobal donothing \ +dontcomplain forgetall donetrue donefalse htdp \ +unvoidbox hfilll vfilll mathbox mathlimop \ +mathnolop mathnothing mathalpha currentcatcodetable defaultcatcodetable \ +catcodetablename newcatcodetable startcatcodetable stopcatcodetable startextendcatcodetable \ +stopextendcatcodetable pushcatcodetable popcatcodetable restorecatcodes setcatcodetable \ +letcatcodecommand defcatcodecommand uedcatcodecommand hglue vglue \ +hfillneg vfillneg hfilllneg vfilllneg ruledhss \ +ruledhfil ruledhfill ruledhfilneg ruledhfillneg normalhfillneg \ +ruledvss ruledvfil ruledvfill ruledvfilneg ruledvfillneg \ +normalvfillneg ruledhbox ruledvbox ruledvtop ruledvcenter \ +ruledmbox ruledhskip ruledvskip ruledkern ruledmskip \ +ruledmkern ruledhglue ruledvglue normalhglue normalvglue \ +ruledpenalty filledhboxb filledhboxr filledhboxg filledhboxc \ +filledhboxm filledhboxy filledhboxk scratchcounter globalscratchcounter \ +scratchdimen globalscratchdimen scratchskip globalscratchskip scratchmuskip \ +globalscratchmuskip scratchtoks globalscratchtoks scratchbox globalscratchbox \ +normalbaselineskip normallineskip normallineskiplimit availablehsize localhsize \ +setlocalhsize nextbox dowithnextbox dowithnextboxcs dowithnextboxcontent \ +dowithnextboxcontentcs scratchwidth scratchheight scratchdepth scratchoffset \ +scratchdistance scratchhsize scratchvsize scratchxoffset scratchyoffset \ +scratchhoffset scratchvoffset scratchxposition scratchyposition scratchtopoffset \ +scratchbottomoffset scratchleftoffset scratchrightoffset scratchcounterone scratchcountertwo \ +scratchcounterthree scratchdimenone scratchdimentwo scratchdimenthree scratchskipone \ +scratchskiptwo scratchskipthree scratchmuskipone scratchmuskiptwo scratchmuskipthree \ +scratchtoksone scratchtokstwo scratchtoksthree scratchboxone scratchboxtwo \ +scratchboxthree scratchnx scratchny scratchmx scratchmy \ +scratchunicode scratchleftskip scratchrightskip scratchtopskip scratchbottomskip \ +doif doifnot doifelse doifinset doifnotinset \ +doifinsetelse doifnextcharelse doifnextoptionalelse doifnextoptionalcselse doiffastoptionalcheckelse \ +doifnextbgroupelse doifnextbgroupcselse doifnextparenthesiselse doifundefinedelse doifdefinedelse \ +doifundefined doifdefined doifelsevalue doifvalue doifnotvalue \ +doifnothing doifsomething doifelsenothing doifsomethingelse doifvaluenothing \ +doifvaluesomething doifelsevaluenothing doifdimensionelse doifnumberelse doifnumber \ +doifnotnumber doifcommonelse doifcommon doifnotcommon doifinstring \ +doifnotinstring doifinstringelse doifassignmentelse docheckassignment tracingall \ +tracingnone loggingall removetoks appendtoks prependtoks \ +appendtotoks prependtotoks to endgraf endpar \ +everyendpar reseteverypar finishpar empty null \ +space quad enspace nbsp obeyspaces \ +obeylines obeyedspace obeyedline obeyedtab obeyedpage \ +normalspace executeifdefined singleexpandafter doubleexpandafter tripleexpandafter \ +dontleavehmode removelastspace removeunwantedspaces keepunwantedspaces wait \ +writestatus define defineexpandable redefine setmeasure \ +setemeasure setgmeasure setxmeasure definemeasure freezemeasure \ +measure measured installcorenamespace getvalue getuvalue \ +setvalue setevalue setgvalue setxvalue letvalue \ +letgvalue resetvalue undefinevalue ignorevalue setuvalue \ +setuevalue setugvalue setuxvalue globallet glet \ +udef ugdef uedef uxdef checked \ +unique getparameters geteparameters getgparameters getxparameters \ +forgetparameters copyparameters getdummyparameters dummyparameter directdummyparameter \ +setdummyparameter letdummyparameter usedummystyleandcolor usedummystyleparameter usedummycolorparameter \ +processcommalist processcommacommand quitcommalist quitprevcommalist processaction \ +processallactions processfirstactioninset processallactionsinset unexpanded expanded \ +startexpanded stopexpanded protected protect unprotect \ +firstofoneargument firstoftwoarguments secondoftwoarguments firstofthreearguments secondofthreearguments \ +thirdofthreearguments firstoffourarguments secondoffourarguments thirdoffourarguments fourthoffourarguments \ +firstoffivearguments secondoffivearguments thirdoffivearguments fourthoffivearguments fifthoffivearguments \ +firstofsixarguments secondofsixarguments thirdofsixarguments fourthofsixarguments fifthofsixarguments \ +sixthofsixarguments firstofoneunexpanded gobbleoneargument gobbletwoarguments gobblethreearguments \ +gobblefourarguments gobblefivearguments gobblesixarguments gobblesevenarguments gobbleeightarguments \ +gobbleninearguments gobbletenarguments gobbleoneoptional gobbletwooptionals gobblethreeoptionals \ +gobblefouroptionals gobblefiveoptionals dorecurse doloop exitloop \ +dostepwiserecurse recurselevel recursedepth dofastloopcs dowith \ +newconstant setnewconstant setconstant setconstantvalue newconditional \ +settrue setfalse settruevalue setfalsevalue newmacro \ +setnewmacro newfraction newsignal dosingleempty dodoubleempty \ +dotripleempty doquadrupleempty doquintupleempty dosixtupleempty doseventupleempty \ +dosingleargument dodoubleargument dotripleargument doquadrupleargument doquintupleargument \ +dosixtupleargument doseventupleargument dosinglegroupempty dodoublegroupempty dotriplegroupempty \ +doquadruplegroupempty doquintuplegroupempty permitspacesbetweengroups dontpermitspacesbetweengroups nopdfcompression \ +maximumpdfcompression normalpdfcompression modulonumber dividenumber getfirstcharacter \ +doiffirstcharelse startnointerference stopnointerference twodigits threedigits \ +leftorright offinterlineskip oninterlineskip nointerlineskip strut \ +setstrut strutbox strutht strutdp strutwd \ +struthtdp begstrut endstrut lineheight ordordspacing \ +ordopspacing ordbinspacing ordrelspacing ordopenspacing ordclosespacing \ +ordpunctspacing ordinnerspacing opordspacing opopspacing opbinspacing \ +oprelspacing opopenspacing opclosespacing oppunctspacing opinnerspacing \ +binordspacing binopspacing binbinspacing binrelspacing binopenspacing \ +binclosespacing binpunctspacing bininnerspacing relordspacing relopspacing \ +relbinspacing relrelspacing relopenspacing relclosespacing relpunctspacing \ +relinnerspacing openordspacing openopspacing openbinspacing openrelspacing \ +openopenspacing openclosespacing openpunctspacing openinnerspacing closeordspacing \ +closeopspacing closebinspacing closerelspacing closeopenspacing closeclosespacing \ +closepunctspacing closeinnerspacing punctordspacing punctopspacing punctbinspacing \ +punctrelspacing punctopenspacing punctclosespacing punctpunctspacing punctinnerspacing \ +innerordspacing inneropspacing innerbinspacing innerrelspacing inneropenspacing \ +innerclosespacing innerpunctspacing innerinnerspacing normalreqno startimath \ +stopimath normalstartimath normalstopimath startdmath stopdmath \ +normalstartdmath normalstopdmath uncramped cramped triggermathstyle \ +mathstylefont mathsmallstylefont mathstyleface mathsmallstyleface mathstylecommand \ +mathpalette mathstylehbox mathstylevbox mathstylevcenter mathstylevcenteredhbox \ +mathstylevcenteredvbox mathtext setmathsmalltextbox setmathtextbox triggerdisplaystyle \ +triggertextstyle triggerscriptstyle triggerscriptscriptstyle triggeruncrampedstyle triggercrampedstyle \ +triggersmallstyle triggeruncrampedsmallstyle triggercrampedsmallstyle triggerbigstyle triggeruncrampedbigstyle \ +triggercrampedbigstyle luaexpr expdoifelse expdoif expdoifnot \ +expdoifcommonelse expdoifinsetelse ctxdirectlua ctxlatelua ctxsprint \ +ctxwrite ctxcommand ctxdirectcommand ctxlatecommand ctxreport \ +ctxlua luacode lateluacode directluacode registerctxluafile \ +ctxloadluafile luaversion luamajorversion luaminorversion ctxluacode \ +luaconditional luaexpanded startluaparameterset stopluaparameterset luaparameterset \ +definenamedlua obeylualines obeyluatokens startluacode stopluacode \ +startlua stoplua startctxfunction stopctxfunction ctxfunction \ +startctxfunctiondefinition stopctxfunctiondefinition carryoverpar assumelongusagecs Umathbotaccent \ +righttolefthbox lefttorighthbox righttoleftvbox lefttorightvbox righttoleftvtop \ +lefttorightvtop rtlhbox ltrhbox rtlvbox ltrvbox \ +rtlvtop ltrvtop autodirhbox autodirvbox autodirvtop \ +lefttoright righttoleft synchronizelayoutdirection synchronizedisplaydirection synchronizeinlinedirection \ +lesshyphens morehyphens nohyphens dohyphens Ucheckedstartdisplaymath \ +Ucheckedstopdisplaymath diff --git a/doc/context/manuals/allkind/mkiv-publications.pdf b/doc/context/manuals/allkind/mkiv-publications.pdf Binary files differindex 8d67cc8cf..1a6d4968e 100644 --- a/doc/context/manuals/allkind/mkiv-publications.pdf +++ b/doc/context/manuals/allkind/mkiv-publications.pdf diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua index 189fc4b7b..70f493525 100644 --- a/scripts/context/lua/mtxrun.lua +++ b/scripts/context/lua/mtxrun.lua @@ -1195,7 +1195,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-table"] = package.loaded["l-table"] or true --- original size: 31828, stripped down to: 20814 +-- original size: 33243, stripped down to: 21578 if not modules then modules={} end modules ['l-table']={ version=1.001, @@ -1342,14 +1342,14 @@ local function sortedhash(t,cmp) end local n=0 local m=#s - local function kv(s) + local function kv() if n<m then n=n+1 local k=s[n] return k,t[k] end end - return kv,s + return kv else return nothing end @@ -2110,6 +2110,44 @@ function table.values(t,s) return {} end end +function table.filtered(t,pattern,sort,cmp) + if t and type(pattern)=="string" then + if sort then + local s + if cmp then + s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) + else + s=sortedkeys(t) + end + local n=0 + local m=#s + local function kv(s) + while n<m do + n=n+1 + local k=s[n] + if find(k,pattern) then + return k,t[k] + end + end + end + return kv,s + else + local n=next(t) + local function iterator() + while n do + local k=n + n=next(t,k) + if find(k,pattern) then + return k,t[k] + end + end + end + return iterator,t + end + else + return nothing + end +end end -- of closure @@ -3775,7 +3813,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-dir"] = package.loaded["l-dir"] or true --- original size: 14788, stripped down to: 9096 +-- original size: 16056, stripped down to: 10707 if not modules then modules={} end modules ['l-dir']={ version=1.001, @@ -3785,7 +3823,7 @@ if not modules then modules={} end modules ['l-dir']={ license="see context related readme files" } local type,select=type,select -local find,gmatch,match,gsub=string.find,string.gmatch,string.match,string.gsub +local find,gmatch,match,gsub,sub=string.find,string.gmatch,string.match,string.gsub,string.sub local concat,insert,remove,unpack=table.concat,table.insert,table.remove,table.unpack local lpegmatch=lpeg.match 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 @@ -3794,54 +3832,123 @@ local dir=dir local lfs=lfs local attributes=lfs.attributes local walkdir=lfs.dir -local isdir=lfs.isdir -local isfile=lfs.isfile +local isdir=lfs.isdir +local isfile=lfs.isfile local currentdir=lfs.currentdir local chdir=lfs.chdir local mkdir=lfs.mkdir local onwindows=os.type=="windows" or find(os.getenv("PATH"),";",1,true) -if not isdir then - function isdir(name) - local a=attributes(name) - return a and a.mode=="directory" +if onwindows then + isdir=function(name) + name=gsub(name,"([/\\]+)$","/.") + return attributes(name,"mode")=="directory" + end + isfile=function(name) + return attributes(name,"mode")=="file" end lfs.isdir=isdir -end -if not isfile then - function isfile(name) - local a=attributes(name) - return a and a.mode=="file" + lfs.isfile=isfile +else + isdir=function(name) + return attributes(name,"mode")=="directory" + end + isfile=function(name) + return attributes(name,"mode")=="file" end + lfs.isdir=isdir lfs.isfile=isfile end function dir.current() return (gsub(currentdir(),"\\","/")) end -local lfsisdir=isdir -local function isdir(path) - path=gsub(path,"[/\\]+$","") - return lfsisdir(path) +local function glob_pattern_function(path,patt,recurse,action) + if isdir(path) then + local usedpath + if path=="/" then + usedpath="/." + elseif not find(path,"/$") then + usedpath=path.."/." + path=path.."/" + else + usedpath=path + end + local dirs + for name in walkdir(usedpath) do + if name~="." and name~=".." then + local full=path..name + local mode=attributes(full,'mode') + if mode=='file' then + if not patt or find(full,patt) then + action(full) + end + elseif recurse and mode=="directory" then + if not dirs then + dirs={ full } + else + dirs[#dirs+1]=full + end + end + end + end + if dirs then + for i=1,#dirs do + glob_pattern_function(dirs[i],patt,recurse,action) + end + end + end end -lfs.isdir=isdir -local function globpattern(path,patt,recurse,action) - if path=="/" then - path=path.."." - elseif not find(path,"/$") then - path=path..'/' - end - if isdir(path) then - for name in walkdir(path) do - local full=path..name - local mode=attributes(full,'mode') - if mode=='file' then - if find(full,patt) then - action(full) +local function glob_pattern_table(path,patt,recurse,result) + if not result then + result={} + end + if isdir(path) then + local usedpath + if path=="/" then + usedpath="/." + elseif not find(path,"/$") then + usedpath=path.."/." + path=path.."/" + else + usedpath=path + end + local dirs + for name in walkdir(usedpath) do + if name~="." and name~=".." then + local full=path..name + local mode=attributes(full,'mode') + if mode=='file' then + if not patt or find(full,patt) then + result[#result+1]=full + end + elseif recurse and mode=="directory" then + if not dirs then + dirs={ full } + else + dirs[#dirs+1]=full + end end - elseif recurse and (mode=="directory") and (name~='.') and (name~="..") then - globpattern(full,patt,recurse,action) + end + end + if dirs then + for i=1,#dirs do + glob_pattern_table(dirs[i],patt,recurse,result) end end end + return result +end +local function globpattern(path,patt,recurse,method) + local kind=type(method) + if pattern and sub(patt,1,-3)==path then + patt=false + end + if kind=="function" then + return glob_pattern_function(path,patt,recurse,method) + elseif kind=="table" then + return glob_pattern_table(path,patt,recurse,method) + else + return glob_pattern_table(path,patt,recurse,{}) + end end dir.globpattern=globpattern local function collectpattern(path,patt,recurse,result) @@ -3853,18 +3960,24 @@ local function collectpattern(path,patt,recurse,result) ok,scanner,first=xpcall(function() return walkdir(path) end,function() end) end if ok and type(scanner)=="function" then - if not find(path,"/$") then path=path..'/' end + if not find(path,"/$") then + path=path..'/' + end for name in scanner,first do - local full=path..name - local attr=attributes(full) - local mode=attr.mode - if mode=='file' then - if find(full,patt) then + if name=="." then + elseif name==".." then + else + 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" then + attr.list=collectpattern(full,patt,recurse) result[name]=attr end - elseif recurse and (mode=="directory") and (name~='.') and (name~="..") then - attr.list=collectpattern(full,patt,recurse) - result[name]=attr end end end @@ -3872,15 +3985,15 @@ local function collectpattern(path,patt,recurse,result) end dir.collectpattern=collectpattern local separator -if onwindows then +if onwindows then local slash=S("/\\")/"/" - pattern=Ct { + pattern={ [1]=(Cs(P(".")+slash^1)+Cs(R("az","AZ")*P(":")*slash^0)+Cc("./"))*V(2)*V(3), [2]=Cs(((1-S("*?/\\"))^0*slash)^0), [3]=Cs(P(1)^0) } -else - pattern=Ct { +else + pattern={ [1]=(C(P(".")+P("/")^1)+Cc("./"))*V(2)*V(3), [2]=C(((1-S("*?/"))^0*P("/"))^0), [3]=C(P(1)^0) @@ -3898,9 +4011,8 @@ local function glob(str,t) elseif 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 root,path,base=lpegmatch(pattern,str) + if root and path and base then local recurse=find(base,"**",1,true) local start=root..path local result=lpegmatch(filter,start..base) @@ -3922,16 +4034,12 @@ local function glob(str,t) return { str } end 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 root,path,base=lpegmatch(pattern,str) + if root and path and base then local recurse=find(base,"**",1,true) local start=root..path local result=lpegmatch(filter,start..base) - globpattern(start,result,recurse,action) - return t + return globpattern(start,result,recurse,t) else return {} end @@ -4879,7 +4987,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-str"] = package.loaded["util-str"] or true --- original size: 33485, stripped down to: 18420 +-- original size: 34240, stripped down to: 18733 if not modules then modules={} end modules ['util-str']={ version=1.001, @@ -5544,6 +5652,15 @@ else add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=lpeg.patterns.texescape }) add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=lpeg.patterns.luaescape }) end +local dquote=patterns.dquote +local equote=patterns.escaped+dquote/'\\"'+1 +local space=patterns.space +local cquote=Cc('"') +local pattern=Cs(dquote*(equote-P(-2))^0*dquote) ++Cs(cquote*(equote-space)^0*space*equote^0*cquote) +function string.optionalquoted(str) + return lpegmatch(pattern,str) or str +end end -- of closure @@ -8717,7 +8834,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-env"] = package.loaded["util-env"] or true --- original size: 8814, stripped down to: 5092 +-- original size: 8022, stripped down to: 5038 if not modules then modules={} end modules ['util-env']={ version=1.001, @@ -8728,7 +8845,7 @@ if not modules then modules={} end modules ['util-env']={ } local allocate,mark=utilities.storage.allocate,utilities.storage.mark local format,sub,match,gsub,find=string.format,string.sub,string.match,string.gsub,string.find -local unquoted,quoted=string.unquoted,string.quoted +local unquoted,quoted,optionalquoted=string.unquoted,string.quoted,string.optionalquoted local concat,insert,remove=table.concat,table.insert,table.remove environment=environment or {} local environment=environment @@ -8841,24 +8958,14 @@ function environment.splitarguments(separator) return before,after end function environment.reconstructcommandline(arg,noquote) + local resolveprefix=resolvers.resolve arg=arg or environment.originalarguments if noquote and #arg==1 then - local a=arg[1] - a=resolvers.resolve(a) - a=unquoted(a) - return a + return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1]) elseif #arg>0 then local result={} for i=1,#arg do - local a=arg[i] - a=resolvers.resolve(a) - a=unquoted(a) - a=gsub(a,'"','\\"') - if find(a," ",1,true) then - result[#result+1]=quoted(a) - else - result[#result+1]=a - end + result[i]=optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix) end return concat(result," ") else @@ -12483,7 +12590,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-ini"] = package.loaded["data-ini"] or true --- original size: 7927, stripped down to: 5528 +-- original size: 10598, stripped down to: 7341 if not modules then modules={} end modules ['data-ini']={ version=1.001, @@ -12492,14 +12599,15 @@ if not modules then modules={} end modules ['data-ini']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files", } +local next,type,getmetatable,rawset=next,type,getmetatable,rawset local gsub,find,gmatch,char=string.gsub,string.find,string.gmatch,string.char -local next,type=next,type local filedirname,filebasename,filejoin=file.dirname,file.basename,file.join +local ostype,osname,osuname,ossetenv,osgetenv=os.type,os.name,os.uname,os.setenv,os.getenv +local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local trace_detail=false trackers.register("resolvers.details",function(v) trace_detail=v end) local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) local report_initialization=logs.reporter("resolvers","initialization") -local ostype,osname,ossetenv,osgetenv=os.type,os.name,os.setenv,os.getenv resolvers=resolvers or {} local resolvers=resolvers texconfig.kpse_init=false @@ -12632,10 +12740,88 @@ if type(profiler)=="table" and not jit then profiler.start("luatex-profile.log") end) end -if not resolvers.resolve then - function resolvers.resolve (s) return s end - function resolvers.unresolve(s) return s end - function resolvers.repath (s) return s end +local prefixes=utilities.storage.allocate() +resolvers.prefixes=prefixes +local resolved={} +local abstract={} +function resolvers.resetresolve(str) + resolved,abstract={},{} +end +function resolvers.allprefixes(separator) + local all=table.sortedkeys(prefixes) + if separator then + for i=1,#all do + all[i]=all[i]..":" + end + end + return all +end +local function _resolve_(method,target) + local action=prefixes[method] + if action then + return action(target) + else + return method..":"..target + end +end +function resolvers.unresolve(str) + return abstract[str] or str +end +local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) +local prefix=C(R("az")^2)*P(":") +local target=C((1-S(" \"\';,"))^1) +local notarget=(#S(";,")+P(-1))*Cc("") +local pattern=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) +local function resolve(str) + if type(str)=="table" then + local res={} + for i=1,#str do + res[i]=resolve(str[i]) + end + return res + else + local res=resolved[str] + if not res then + res=lpegmatch(pattern,str) + resolved[str]=res + abstract[res]=str + end + return res + end +end +resolvers.resolve=resolve +if type(osuname)=="function" then + for k,v in next,osuname() do + if not prefixes[k] then + prefixes[k]=function() return v end + end + end +end +if ostype=="unix" then + local pattern + local function makepattern(t,k,v) + if t then + rawset(t,k,v) + end + local colon=P(":") + for k,v in table.sortedpairs(prefixes) do + if p then + p=P(k)+p + else + p=P(k) + end + end + pattern=Cs((p*colon+colon/";"+P(1))^0) + end + makepattern() + table.setmetatablenewindex(prefixes,makepattern) + function resolvers.repath(str) + return lpegmatch(pattern,str) + end +else + function resolvers.repath(str) + return str + end end @@ -12645,7 +12831,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-exp"] = package.loaded["data-exp"] or true --- original size: 15317, stripped down to: 9723 +-- original size: 16463, stripped down to: 10113 if not modules then modules={} end modules ['data-exp']={ version=1.001, @@ -12660,11 +12846,14 @@ local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns local Ct,Cs,Cc,Carg,P,C,S=lpeg.Ct,lpeg.Cs,lpeg.Cc,lpeg.Carg,lpeg.P,lpeg.C,lpeg.S local type,next=type,next local ostype=os.type -local collapsepath=file.collapsepath +local collapsepath,joinpath,basename=file.collapsepath,file.join,file.basename local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_globbing=true trackers.register("resolvers.globbing",function(v) trace_globbing=v end) local report_expansions=logs.reporter("resolvers","expansions") +local report_globbing=logs.reporter("resolvers","globbing") local resolvers=resolvers +local resolveprefix=resolvers.resolve local function f_both(a,b) local t,n={},0 for sb in gmatch(b,"[^,]+") do @@ -12754,35 +12943,27 @@ function resolvers.expandedpathfromlist(pathlist) end return newlist end -local cleanup=lpeg.replacer { - { "!","" }, - { "\\","/" }, -} -function resolvers.cleanpath(str) - local doslashes=(P("\\")/"/"+1)^0 - local donegation=(P("!")/"" )^0 - local homedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") - if homedir=="~" or homedir=="" or not lfs.isdir(homedir) then - if trace_expansions then - report_expansions("no home dir set, ignoring dependent paths") - end - function resolvers.cleanpath(str) - if not str or find(str,"~",1,true) then - return "" - else - return lpegmatch(cleanup,str) +local usedhomedir=nil +local donegation=(P("!")/"" )^0 +local doslashes=(P("\\")/"/"+1)^0 +local function expandedhome() + if not usedhomedir then + usedhomedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") + if usedhomedir=="~" or usedhomedir=="" or not lfs.isdir(usedhomedir) then + if trace_expansions then + report_expansions("no home dir set, ignoring dependent path using current path") end - end - else - local dohome=((P("~")+P("$HOME"))/homedir)^0 - local cleanup=Cs(donegation*dohome*doslashes) - function resolvers.cleanpath(str) - return str and lpegmatch(cleanup,str) or "" + usedhomedir="." end end - return resolvers.cleanpath(str) + return usedhomedir +end +local dohome=((P("~")+P("$HOME")+P("%HOME%"))/expandedhome)^0 +local cleanup=Cs(donegation*dohome*doslashes) +resolvers.cleanpath=function(str) + return str and lpegmatch(cleanup,str) or "" end -local expandhome=P("~")/"$HOME" +local expandhome=P("~")/"$HOME" local dodouble=P('"')/""*(expandhome+(1-P('"')))^0*P('"')/"" local dosingle=P("'")/""*(expandhome+(1-P("'")))^0*P("'")/"" local dostring=(expandhome+1 )^0 @@ -12834,7 +13015,7 @@ function resolvers.splitpath(str) end function resolvers.joinpath(str) if type(str)=='table' then - return file.joinpath(str) + return joinpath(str) else return str end @@ -12845,35 +13026,54 @@ local timer={} local scanned={} local nofscans=0 local scancache={} -local function scan(files,spec,path,n,m,r) - local full=(path=="" and spec) or (spec..path..'/') +local fullcache={} +local nofsharedscans=0 +local function scan(files,remap,spec,path,n,m,r,onlyone) + local full=path=="" and spec or (spec..path..'/') local dirs={} local nofdirs=0 for name in directory(full) do if not lpegmatch(weird,name) then - local mode=attributes(full..name,'mode') - if mode=='file' then + local mode=attributes(full..name,"mode") + if mode=="file" then n=n+1 - local f=files[name] - if f then - if type(f)=='string' then - files[name]={ f,path } + local lower=lower(name) + local paths=files[lower] + if paths then + if onlyone then else - f[#f+1]=path + if type(paths)=="string" then + files[lower]={ paths,path } + else + paths[#paths+1]=path + end + if name~=lower then + local rl=remap[lower] + if not rl then + remap[lower]=name + r=r+1 + elseif trace_globbing and rl~=name then + report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) + end + end end else - files[name]=path - local lower=lower(name) + files[lower]=path if name~=lower then - files["remap:"..lower]=name - r=r+1 + local rl=remap[lower] + if not rl then + remap[lower]=name + r=r+1 + elseif trace_globbing and rl~=name then + report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) + end end end - elseif mode=='directory' then + elseif mode=="directory" then m=m+1 nofdirs=nofdirs+1 if path~="" then - dirs[nofdirs]=path..'/'..name + dirs[nofdirs]=path.."/"..name else dirs[nofdirs]=name end @@ -12883,107 +13083,52 @@ local function scan(files,spec,path,n,m,r) if nofdirs>0 then sort(dirs) for i=1,nofdirs do - files,n,m,r=scan(files,spec,dirs[i],n,m,r) + files,remap,n,m,r=scan(files,remap,spec,dirs[i],n,m,r,onlyone) end end scancache[sub(full,1,-2)]=files - return files,n,m,r + return files,remap,n,m,r end -local fullcache={} -function resolvers.scanfiles(path,branch,usecache) - statistics.starttiming(timer) - local realpath=resolvers.resolve(path) +function resolvers.scanfiles(path,branch,usecache,onlyonce) + local realpath=resolveprefix(path) if usecache then - local files=fullcache[realpath] - if files then + local content=fullcache[realpath] + if content then if trace_locating then - report_expansions("using caches scan of path %a, branch %a",path,branch or path) + report_expansions("using cached scan of path %a, branch %a",path,branch or path) end - return files + nofsharedscans=nofsharedscans+1 + return content end end + statistics.starttiming(timer) if trace_locating then report_expansions("scanning path %a, branch %a",path,branch or path) end - local files,n,m,r=scan({},realpath..'/',"",0,0,0) - files.__path__=path - files.__files__=n - files.__directories__=m - files.__remappings__=r + local files,remap,n,m,r=scan({},{},realpath..'/',"",0,0,0,onlyonce) + local content={ + metadata={ + path=path, + files=n, + directories=m, + remappings=r, + }, + files=files, + remap=remap, + } if trace_locating then report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r) end if usecache then scanned[#scanned+1]=realpath - fullcache[realpath]=files + fullcache[realpath]=content end nofscans=nofscans+1 statistics.stoptiming(timer) - return files -end -local function simplescan(files,spec,path) - local full=(path=="" and spec) or (spec..path..'/') - local dirs={} - local nofdirs=0 - for name in directory(full) do - if not lpegmatch(weird,name) then - local mode=attributes(full..name,'mode') - if mode=='file' then - if not files[name] then - files[name]=path - end - elseif mode=='directory' then - nofdirs=nofdirs+1 - if path~="" then - dirs[nofdirs]=path..'/'..name - else - dirs[nofdirs]=name - end - end - end - end - if nofdirs>0 then - sort(dirs) - for i=1,nofdirs do - files=simplescan(files,spec,dirs[i]) - end - end - return files + return content end -local simplecache={} -local nofsharedscans=0 function resolvers.simplescanfiles(path,branch,usecache) - statistics.starttiming(timer) - local realpath=resolvers.resolve(path) - if usecache then - local files=simplecache[realpath] - if not files then - files=scancache[realpath] - if files then - nofsharedscans=nofsharedscans+1 - end - end - if files then - if trace_locating then - report_expansions("using caches scan of path %a, branch %a",path,branch or path) - end - return files - end - end - if trace_locating then - report_expansions("scanning path %a, branch %a",path,branch or path) - end - local files=simplescan({},realpath..'/',"") - if trace_locating then - report_expansions("%s files found",table.count(files)) - end - if usecache then - scanned[#scanned+1]=realpath - simplecache[realpath]=files - end - nofscans=nofscans+1 - statistics.stoptiming(timer) - return files + return resolvers.scanfiles(path,branch,usecache,true) end function resolvers.scandata() table.sort(scanned) @@ -12994,6 +13139,49 @@ function resolvers.scandata() paths=scanned, } end +function resolvers.get_from_content(content,path,name) + local files=content.files + if not files then + return + end + local remap=content.remap + if not remap then + return + end + if name then + local used=lower(name) + return path,remap[used] or used + else + local name=path + local used=lower(name) + local path=files[used] + if path then + return path,remap[used] or used + end + end +end +local nothing=function() end +function resolvers.filtered_from_content(content,pattern) + if content and type(pattern)=="string" then + local pattern=lower(pattern) + local files=content.files + local remap=content.remap + if files and remap then + local n=next(files) + local function iterator() + while n do + local k=n + n=next(files,k) + if find(k,pattern) then + return files[k],remap and remap[k] or k + end + end + end + return iterator + end + end + return nothing +end end -- of closure @@ -13272,7 +13460,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tmp"] = package.loaded["data-tmp"] or true --- original size: 15532, stripped down to: 11648 +-- original size: 15681, stripped down to: 11761 if not modules then modules={} end modules ['data-tmp']={ version=1.100, @@ -13291,6 +13479,7 @@ local trace_cache=false trackers.register("resolvers.cache",function(v) trace_ca local report_caches=logs.reporter("resolvers","caches") local report_resolvers=logs.reporter("resolvers","caching") local resolvers=resolvers +local cleanpath=resolvers.cleanpath local directive_cleanup=false directives.register("system.compile.cleanup",function(v) directive_cleanup=v end) local directive_strip=false directives.register("system.compile.strip",function(v) directive_strip=v end) local compile=utilities.lua.compile @@ -13312,7 +13501,7 @@ caches.relocate=false caches.defaults={ "TMPDIR","TEMPDIR","TMP","TEMP","HOME","HOMEPATH" } local writable,readables,usedreadables=nil,{},{} local function identify() - local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") + local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") if texmfcaches then for k=1,#texmfcaches do local cachepath=texmfcaches[k] @@ -13566,10 +13755,12 @@ local content_state={} function caches.contentstate() return content_state or {} end -function caches.loadcontent(cachename,dataname) - local name=caches.hashed(cachename) - local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") - local filename=file.join(path,name) +function caches.loadcontent(cachename,dataname,filename) + if not filename then + local name=caches.hashed(cachename) + local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") + filename=file.join(path,name) + end local blob=loadfile(addsuffix(filename,luasuffixes.luc)) or loadfile(addsuffix(filename,luasuffixes.lua)) if blob then local data=blob() @@ -13601,10 +13792,12 @@ function caches.collapsecontent(content) end end end -function caches.savecontent(cachename,dataname,content) - local name=caches.hashed(cachename) - local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") - local filename=file.join(path,name) +function caches.savecontent(cachename,dataname,content,filename) + if not filename then + local name=caches.hashed(cachename) + local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") + filename=file.join(path,name) + end local luaname=addsuffix(filename,luasuffixes.lua) local lucname=addsuffix(filename,luasuffixes.luc) if trace_locating then @@ -13647,7 +13840,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-met"] = package.loaded["data-met"] or true --- original size: 5460, stripped down to: 4014 +-- original size: 5347, stripped down to: 4015 if not modules then modules={} end modules ['data-met']={ version=1.100, @@ -13675,7 +13868,7 @@ local function splitmethod(filename) if type(filename)=="table" then return filename end - filename=file.collapsepath(filename,".") + filename=file.collapsepath(filename,".") if not find(filename,"://",1,true) then return { scheme="file",path=filename,original=filename,filename=filename } end @@ -13766,7 +13959,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-res"] = package.loaded["data-res"] or true --- original size: 62045, stripped down to: 43116 +-- original size: 61031, stripped down to: 42613 if not modules then modules={} end modules ['data-res']={ version=1.001, @@ -13776,7 +13969,7 @@ if not modules then modules={} end modules ['data-res']={ license="see context related readme files", } local gsub,find,lower,upper,match,gmatch=string.gsub,string.find,string.lower,string.upper,string.match,string.gmatch -local concat,insert,sortedkeys=table.concat,table.insert,table.sortedkeys +local concat,insert,sortedkeys,sortedhash=table.concat,table.insert,table.sortedkeys,table.sortedhash local next,type,rawget=next,type,rawget local os=os local P,S,R,C,Cc,Cs,Ct,Carg=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cc,lpeg.Cs,lpeg.Ct,lpeg.Carg @@ -13785,14 +13978,19 @@ local formatters=string.formatters local filedirname=file.dirname local filebasename=file.basename local suffixonly=file.suffixonly +local addsuffix=file.addsuffix +local removesuffix=file.removesuffix local filejoin=file.join local collapsepath=file.collapsepath local joinpath=file.joinpath +local is_qualified_path=file.is_qualified_path local allocate=utilities.storage.allocate local settings_to_array=utilities.parsers.settings_to_array +local getcurrentdir=lfs.currentdir +local isfile=lfs.isfile +local isdir=lfs.isdir local setmetatableindex=table.setmetatableindex local luasuffixes=utilities.lua.suffixes -local getcurrentdir=lfs.currentdir local trace_locating=false trackers .register("resolvers.locating",function(v) trace_locating=v end) local trace_detail=false trackers .register("resolvers.details",function(v) trace_detail=v end) local trace_expansions=false trackers .register("resolvers.expansions",function(v) trace_expansions=v end) @@ -13803,10 +14001,14 @@ local expandedpathfromlist=resolvers.expandedpathfromlist local checkedvariable=resolvers.checkedvariable local splitconfigurationpath=resolvers.splitconfigurationpath local methodhandler=resolvers.methodhandler +local filtered=resolvers.filtered_from_content +local lookup=resolvers.get_from_content +local cleanpath=resolvers.cleanpath +local resolveprefix=resolvers.resolve local initializesetter=utilities.setters.initialize local ostype,osname,osenv,ossetenv,osgetenv=os.type,os.name,os.env,os.setenv,os.getenv -resolvers.cacheversion='1.0.1' -resolvers.configbanner='' +resolvers.cacheversion="1.100" +resolvers.configbanner="" resolvers.homedir=environment.homedir resolvers.criticalvars=allocate { "SELFAUTOLOC","SELFAUTODIR","SELFAUTOPARENT","TEXMFCNF","TEXMF","TEXOS" } resolvers.luacnfname="texmfcnf.lua" @@ -13833,7 +14035,7 @@ local instance=resolvers.instance or nil function resolvers.setenv(key,value,raw) if instance then instance.environment[key]=value - ossetenv(key,raw and value or resolvers.resolve(value)) + ossetenv(key,raw and value or resolveprefix(value)) end end local function getenv(key) @@ -13847,7 +14049,7 @@ local function getenv(key) end resolvers.getenv=getenv resolvers.env=getenv -local function resolve(k) +local function resolvevariable(k) return instance.expansions[k] end local dollarstripper=lpeg.stripper("$") @@ -13856,19 +14058,19 @@ local backslashswapper=lpeg.replacer("\\","/") local somevariable=P("$")/"" local somekey=C(R("az","AZ","09","__","--")^1) local somethingelse=P(";")*((1-S("!{}/\\"))^1*P(";")/"")+P(";")*(P(";")/"")+P(1) -local variableexpander=Cs((somevariable*(somekey/resolve)+somethingelse)^1 ) +local variableexpander=Cs((somevariable*(somekey/resolvevariable)+somethingelse)^1 ) local cleaner=P("\\")/"/"+P(";")*S("!{}/\\")^0*P(";")^1/";" local variablecleaner=Cs((cleaner+P(1))^0) -local somevariable=R("az","AZ","09","__","--")^1/resolve +local somevariable=R("az","AZ","09","__","--")^1/resolvevariable local variable=(P("$")/"")*(somevariable+(P("{")/"")*somevariable*(P("}")/"")) local variableresolver=Cs((variable+P(1))^0) local function expandedvariable(var) return lpegmatch(variableexpander,var) or var end -function resolvers.newinstance() - if trace_locating then +function resolvers.newinstance() + if trace_locating then report_resolving("creating instance") - end + end local environment,variables,expansions,order=allocate(),allocate(),allocate(),allocate() local newinstance={ environment=environment, @@ -13995,13 +14197,13 @@ local function identify_configuration_files() for i=1,#cnfpaths do local filepath=cnfpaths[i] local filename=collapsepath(filejoin(filepath,luacnfname)) - local realname=resolvers.resolve(filename) + local realname=resolveprefix(filename) if trace_locating then - local fullpath=gsub(resolvers.resolve(collapsepath(filepath)),"//","/") + local fullpath=gsub(resolveprefix(collapsepath(filepath)),"//","/") local weirdpath=find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c",1,true) report_resolving("looking for %a on %s path %a from specification %a",luacnfname,weirdpath and "weird" or "given",fullpath,filepath) end - if lfs.isfile(realname) then + if isfile(realname) then specification[#specification+1]=filename if trace_locating then report_resolving("found configuration file %a",realname) @@ -14023,7 +14225,7 @@ local function load_configuration_files() local filename=specification[i] local pathname=filedirname(filename) local filename=filejoin(pathname,luacnfname) - local realname=resolvers.resolve(filename) + local realname=resolveprefix(filename) local blob=loadfile(realname) if blob then local setups=instance.setups @@ -14031,7 +14233,7 @@ local function load_configuration_files() local parent=data and data.parent if parent then local filename=filejoin(pathname,parent) - local realname=resolvers.resolve(filename) + local realname=resolveprefix(filename) local blob=loadfile(realname) if blob then local parentdata=blob() @@ -14056,7 +14258,7 @@ local function load_configuration_files() elseif variables[k]==nil then if trace_locating and not warning then report_resolving("variables like %a in configuration file %a should move to the 'variables' subtable", - k,resolvers.resolve(filename)) + k,resolveprefix(filename)) warning=true end variables[k]=v @@ -14116,7 +14318,7 @@ local function locate_file_databases() local stripped=lpegmatch(inhibitstripper,path) if stripped~="" then local runtime=stripped==path - path=resolvers.cleanpath(path) + path=cleanpath(path) local spec=resolvers.splitmethod(stripped) if runtime and (spec.noscheme or spec.scheme=="file") then stripped="tree:///"..stripped @@ -14179,8 +14381,8 @@ function resolvers.renew(hashname) report_resolving("identifying tree %a",hashname) end end - local realpath=resolvers.resolve(hashname) - if lfs.isdir(realpath) then + local realpath=resolveprefix(hashname) + if isdir(realpath) then if trace_locating then report_resolving("using path %a",realpath) end @@ -14308,7 +14510,7 @@ function resolvers.registerextrapath(paths,subpaths) local ps=p.."/"..s if not done[ps] then newn=newn+1 - ep[newn]=resolvers.cleanpath(ps) + ep[newn]=cleanpath(ps) done[ps]=true end end @@ -14318,7 +14520,7 @@ function resolvers.registerextrapath(paths,subpaths) local p=paths[i] if not done[p] then newn=newn+1 - ep[newn]=resolvers.cleanpath(p) + ep[newn]=cleanpath(p) done[p]=true end end @@ -14330,7 +14532,7 @@ function resolvers.registerextrapath(paths,subpaths) local ps=ep[i].."/"..s if not done[ps] then newn=newn+1 - ep[newn]=resolvers.cleanpath(ps) + ep[newn]=cleanpath(ps) done[ps]=true end end @@ -14384,7 +14586,7 @@ function resolvers.cleanpathlist(str) local t=resolvers.expandedpathlist(str) if t then for i=1,#t do - t[i]=collapsepath(resolvers.cleanpath(t[i])) + t[i]=collapsepath(cleanpath(t[i])) end end return t @@ -14434,7 +14636,7 @@ function resolvers.registerfilehash(name,content,someerror) end end local function isreadable(name) - local readable=lfs.isfile(name) + local readable=isfile(name) if trace_detail then if readable then report_resolving("file %a is readable",name) @@ -14445,69 +14647,56 @@ local function isreadable(name) return readable end local function collect_files(names) - local filelist,noffiles={},0 + local filelist={} + local noffiles=0 + local function check(hash,root,pathname,path,name) + if not pathname or find(path,pathname) then + local variant=hash.type + local search=filejoin(root,path,name) + local result=methodhandler('concatinators',variant,root,path,name) + if trace_detail then + report_resolving("match: variant %a, search %a, result %a",variant,search,result) + end + noffiles=noffiles+1 + filelist[noffiles]={ variant,search,result } + end + end for k=1,#names do - local fname=names[k] + local filename=names[k] if trace_detail then - report_resolving("checking name %a",fname) + report_resolving("checking name %a",filename) end - local bname=filebasename(fname) - local dname=filedirname(fname) - if dname=="" or find(dname,"^%.") then - dname=false + local basename=filebasename(filename) + local pathname=filedirname(filename) + if pathname=="" or find(pathname,"^%.") then + pathname=false else - dname=gsub(dname,"%*",".*") - dname="/"..dname.."$" + pathname=gsub(pathname,"%*",".*") + pathname="/"..pathname.."$" end local hashes=instance.hashes for h=1,#hashes do local hash=hashes[h] - local blobpath=hash.name - local files=blobpath and instance.files[blobpath] - if files then + local hashname=hash.name + local content=hashname and instance.files[hashname] + if content then if trace_detail then - report_resolving("deep checking %a, base %a, pattern %a",blobpath,bname,dname) - 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 + report_resolving("deep checking %a, base %a, pattern %a",blobpath,basename,pathname) end - if blobfile then - local blobroot=files.__path__ or blobpath - if type(blobfile)=='string' then - if not dname or find(blobfile,dname) then - local variant=hash.type - local search=filejoin(blobroot,blobfile,bname) - local result=methodhandler('concatinators',hash.type,blobroot,blobfile,bname) - if trace_detail then - report_resolving("match: variant %a, search %a, result %a",variant,search,result) - end - noffiles=noffiles+1 - filelist[noffiles]={ variant,search,result } - end + local path,name=lookup(content,basename) + if path then + local metadata=content.metadata + local realroot=metadata and metadata.path or hashname + if type(path)=="string" then + check(hash,realroot,pathname,path,name) else - for kk=1,#blobfile do - local vv=blobfile[kk] - if not dname or find(vv,dname) then - local variant=hash.type - local search=filejoin(blobroot,vv,bname) - local result=methodhandler('concatinators',hash.type,blobroot,vv,bname) - if trace_detail then - report_resolving("match: variant %a, search %a, result %a",variant,search,result) - end - noffiles=noffiles+1 - filelist[noffiles]={ variant,search,result } - end + for i=1,#path do + check(hash,realroot,pathname,path[i],name) end end end elseif trace_locating then - report_resolving("no match in %a (%s)",blobpath,bname) + report_resolving("no match in %a (%s)",hashname,basename) end end end @@ -14532,7 +14721,7 @@ end local function can_be_dir(name) local fakepaths=instance.fakepaths if not fakepaths[name] then - if lfs.isdir(name) then + if isdir(name) then fakepaths[name]=1 else fakepaths[name]=2 @@ -14548,10 +14737,11 @@ local function find_analyze(filename,askedformat,allresults) if askedformat=="" then if ext=="" or not suffixmap[ext] then local defaultsuffixes=resolvers.defaultsuffixes + local formatofsuffix=resolvers.formatofsuffix for i=1,#defaultsuffixes do local forcedname=filename..'.'..defaultsuffixes[i] wantedfiles[#wantedfiles+1]=forcedname - filetype=resolvers.formatofsuffix(forcedname) + filetype=formatofsuffix(forcedname) if trace_locating then report_resolving("forcing filetype %a",filetype) end @@ -14591,14 +14781,14 @@ local function find_wildcard(filename,allresults) if trace_locating then report_resolving("checking wildcard %a",filename) end - local method,result=resolvers.findwildcardfiles(filename) + local result=resolvers.findwildcardfiles(filename) if result then return "wildcard",result end end end local function find_qualified(filename,allresults,askedformat,alsostripped) - if not file.is_qualified_path(filename) then + if not is_qualified_path(filename) then return end if trace_locating then @@ -14687,7 +14877,6 @@ local function find_intree(filename,filetype,wantedfiles,allresults) if trace_detail then report_resolving("checking filename %a",filename) end - local resolve=resolvers.resolve local result={} for k=1,#pathlist do local path=pathlist[k] @@ -14706,8 +14895,8 @@ local function find_intree(filename,filetype,wantedfiles,allresults) local fl=filelist[k] local f=fl[2] local d=dirlist[k] - if find(d,expression) or find(resolve(d),expression) then - result[#result+1]=resolve(fl[3]) + if find(d,expression) or find(resolveprefix(d),expression) then + result[#result+1]=resolveprefix(fl[3]) done=true if allresults then if trace_detail then @@ -14729,7 +14918,7 @@ local function find_intree(filename,filetype,wantedfiles,allresults) else method="filesystem" pathname=gsub(pathname,"/+$","") - pathname=resolve(pathname) + pathname=resolveprefix(pathname) local scheme=url.hasscheme(pathname) if not scheme or scheme=="file" then local pname=gsub(pathname,"%.%*$",'') @@ -14819,7 +15008,7 @@ local function find_otherwise(filename,filetype,wantedfiles,allresults) local filelist=collect_files(wantedfiles) local fl=filelist and filelist[1] if fl then - return "otherwise",{ resolvers.resolve(fl[3]) } + return "otherwise",{ resolveprefix(fl[3]) } end end collect_instance_files=function(filename,askedformat,allresults) @@ -14919,39 +15108,30 @@ function resolvers.findpath(filename,filetype) return filedirname(findfiles(filename,filetype,false)[1] or "") end local function findgivenfiles(filename,allresults) - local bname,result=filebasename(filename),{} + local base=filebasename(filename) + local result={} local hashes=instance.hashes - local noffound=0 + local function okay(hash,path,name) + local found=methodhandler('concatinators',hash.type,hash.name,path,name) + if found and found~="" then + result[#result+1]=resolveprefix(found) + return not allresults + end + end for k=1,#hashes do local hash=hashes[k] - local files=instance.files[hash.name] 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 - local found=methodhandler('concatinators',hash.type,hash.name,blist,bname) or "" - if found~="" then - noffound=noffound+1 - result[noffound]=resolvers.resolve(found) - if not allresults then - break - end + local content=instance.files[hash.name] + if content then + local path,name=lookup(content,base) + if not path then + elseif type(path)=="string" then + if okay(hash,path,name) then + return result end else - for kk=1,#blist do - local vv=blist[kk] - local found=methodhandler('concatinators',hash.type,hash.name,vv,bname) or "" - if found~="" then - noffound=noffound+1 - result[noffound]=resolvers.resolve(found) - if not allresults then break end + for i=1,#path do + if okay(hash,path[i],name) then + return result end end end @@ -14965,64 +15145,80 @@ end function resolvers.findgivenfile(filename) return findgivenfiles(filename,false)[1] or "" end -local function doit(path,blist,bname,tag,variant,result,allresults) - local done=false - if blist and variant then - local resolve=resolvers.resolve - if type(blist)=='string' then - if find(lower(blist),path) then - local full=methodhandler('concatinators',variant,tag,blist,bname) or "" - result[#result+1]=resolve(full) - done=true - end - else - for kk=1,#blist do - local vv=blist[kk] - if find(lower(vv),path) then - local full=methodhandler('concatinators',variant,tag,vv,bname) or "" - result[#result+1]=resolve(full) - done=true - if not allresults then break end - end - end - end - end - return done -end local makewildcard=Cs( (P("^")^0*P("/")*P(-1)+P(-1))/".*"+(P("^")^0*P("/")/"")^0*(P("*")/".*"+P("-")/"%%-"+P(".")/"%%."+P("?")/"."+P("\\")/"/"+P(1))^0 ) function resolvers.wildcardpattern(pattern) return lpegmatch(makewildcard,pattern) or pattern end -local function findwildcardfiles(filename,allresults,result) - result=result or {} +local function findwildcardfiles(filename,allresults,result) + local result=result or {} local base=filebasename(filename) local dirn=filedirname(filename) local path=lower(lpegmatch(makewildcard,dirn) or dirn) local name=lower(lpegmatch(makewildcard,base) or base) - local files,done=instance.files,false + local files=instance.files if find(name,"*",1,true) then local hashes=instance.hashes + local function okay(found,path,base,hashname,hashtype) + if find(found,path) then + local full=methodhandler('concatinators',hashtype,hashname,found,base) + if full and full~="" then + result[#result+1]=resolveprefix(full) + return not allresults + end + end + end for k=1,#hashes do local hash=hashes[k] - local hashname,hashtype=hash.name,hash.type - for kk,hh in next,files[hashname] do - if not find(kk,"^remap:") then - if find(lower(kk),name) then - if doit(path,hh,kk,hashname,hashtype,result,allresults) then done=true end - if done and not allresults then break end + local hashname=hash.name + local hashtype=hash.type + if hashname and hashtype then + for found,base in filtered(files[hashname],name) do + if type(found)=='string' then + if okay(found,path,base,hashname,hashtype) then + break + end + else + for i=1,#found do + if okay(found[i],path,base,hashname,hashtype) then + break + end + end end end end end else + local function okayokay(found,path,base,hashname,hashtype) + if find(found,path) then + local full=methodhandler('concatinators',hashtype,hashname,found,base) + if full and full~="" then + result[#result+1]=resolveprefix(full) + return not allresults + end + end + end local hashes=instance.hashes for k=1,#hashes do local hash=hashes[k] - local hashname,hashtype=hash.name,hash.type - if doit(path,files[hashname][base],base,hashname,hashtype,result,allresults) then done=true end - if done and not allresults then break end + local hashname=hash.name + local hashtype=hash.type + if hashname and hashtype then + local found,base=lookup(content,base) + if not found then + elseif type(found)=='string' then + if okay(found,path,base,hashname,hashtype) then + break + end + else + for i=1,#found do + if okay(found[i],path,base,hashname,hashtype) then + break + end + end + end + end end end return result @@ -15095,7 +15291,7 @@ end function resolvers.dowithpath(name,func) local pathlist=resolvers.expandedpathlist(name) for i=1,#pathlist do - func("^"..resolvers.cleanpath(pathlist[i])) + func("^"..cleanpath(pathlist[i])) end end function resolvers.dowithvariable(name,func) @@ -15103,23 +15299,23 @@ function resolvers.dowithvariable(name,func) end function resolvers.locateformat(name) local engine=environment.ownmain or "luatex" - local barename=file.removesuffix(name) - local fullname=file.addsuffix(barename,"fmt") + local barename=removesuffix(name) + local fullname=addsuffix(barename,"fmt") local fmtname=caches.getfirstreadablefile(fullname,"formats",engine) or "" if fmtname=="" then fmtname=resolvers.findfile(fullname) - fmtname=resolvers.cleanpath(fmtname) + fmtname=cleanpath(fmtname) end if fmtname~="" then - local barename=file.removesuffix(fmtname) - local luaname=file.addsuffix(barename,luasuffixes.lua) - local lucname=file.addsuffix(barename,luasuffixes.luc) - local luiname=file.addsuffix(barename,luasuffixes.lui) - if lfs.isfile(luiname) then + local barename=removesuffix(fmtname) + local luaname=addsuffix(barename,luasuffixes.lua) + local lucname=addsuffix(barename,luasuffixes.luc) + local luiname=addsuffix(barename,luasuffixes.lui) + if isfile(luiname) then return barename,luiname - elseif lfs.isfile(lucname) then + elseif isfile(lucname) then return barename,lucname - elseif lfs.isfile(luaname) then + elseif isfile(luaname) then return barename,luaname end end @@ -15141,29 +15337,24 @@ function resolvers.dowithfilesintree(pattern,handle,before,after) local hash=hashes[i] local blobtype=hash.type local blobpath=hash.name - if blobpath then + if blobtype and blobpath then + local total=0 + local checked=0 + local done=0 if before then before(blobtype,blobpath,pattern) end - local files=instance.files[blobpath] - local total,checked,done=0,0,0 - if files then - for k,v in table.sortedhash(files) do - total=total+1 - if find(k,"^remap:") then - elseif find(k,pattern) then - if type(v)=="string" then - checked=checked+1 - if handle(blobtype,blobpath,v,k) then - done=done+1 - end - else - checked=checked+#v - for i=1,#v do - if handle(blobtype,blobpath,v[i],k) then - done=done+1 - end - end + for path,name in filtered(instance.files[blobpath],pattern) do + if type(path)=="string" then + checked=checked+1 + if handle(blobtype,blobpath,path,name) then + done=done+1 + end + else + checked=checked+#path + for i=1,#path do + if handle(blobtype,blobpath,path[i],name) then + done=done+1 end end end @@ -15174,8 +15365,8 @@ function resolvers.dowithfilesintree(pattern,handle,before,after) end end end -resolvers.obsolete=resolvers.obsolete or {} -local obsolete=resolvers.obsolete +local obsolete=resolvers.obsolete or {} +resolvers.obsolete=obsolete resolvers.find_file=resolvers.findfile obsolete.find_file=resolvers.findfile resolvers.find_files=resolvers.findfiles obsolete.find_files=resolvers.findfiles @@ -15186,7 +15377,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-pre"] = package.loaded["data-pre"] or true --- original size: 6643, stripped down to: 4401 +-- original size: 3106, stripped down to: 2563 if not modules then modules={} end modules ['data-pre']={ version=1.001, @@ -15196,44 +15387,51 @@ if not modules then modules={} end modules ['data-pre']={ license="see context related readme files" } local resolvers=resolvers -local prefixes=utilities.storage.allocate() -resolvers.prefixes=prefixes -local cleanpath,findgivenfile,expansion=resolvers.cleanpath,resolvers.findgivenfile,resolvers.expansion +local prefixes=resolvers.prefixes +local cleanpath=resolvers.cleanpath +local findgivenfile=resolvers.findgivenfile +local expansion=resolvers.expansion local getenv=resolvers.getenv -local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match -local joinpath,basename,dirname=file.join,file.basename,file.dirname -local getmetatable,rawset,type=getmetatable,rawset,type +local basename=file.basename +local dirname=file.dirname +local joinpath=file.join +local isfile=lfs.isfile prefixes.environment=function(str) return cleanpath(expansion(str)) end -prefixes.relative=function(str,n) - if io.exists(str) then - elseif io.exists("./"..str) then - str="./"..str - else - local p="../" - for i=1,n or 2 do - if io.exists(p..str) then - str=p..str - break - else - p=p.."../" +local function relative(str,n) + if not isfile(str) then + local pstr="./"..str + if isfile(pstr) then + str=pstr + else + local p="../" + for i=1,n or 2 do + local pstr=p..str + if isfile(pstr) then + str=pstr + break + else + p=p.."../" + end end end end return cleanpath(str) end +local function locate(str) + local fullname=findgivenfile(str) or "" + return cleanpath(fullname~="" and fullname or str) +end +prefixes.relative=relative +prefixes.locate=locate prefixes.auto=function(str) - local fullname=prefixes.relative(str) - if not lfs.isfile(fullname) then - fullname=prefixes.locate(str) + local fullname=relative(str) + if not isfile(fullname) then + fullname=locate(str) end return fullname end -prefixes.locate=function(str) - local fullname=findgivenfile(str) or "" - return cleanpath((fullname~="" and fullname) or str) -end prefixes.filename=function(str) local fullname=findgivenfile(str) or "" return cleanpath(basename((fullname~="" and fullname) or str)) @@ -15277,87 +15475,6 @@ prefixes.kpse=prefixes.locate prefixes.full=prefixes.locate prefixes.file=prefixes.filename prefixes.path=prefixes.pathname -function resolvers.allprefixes(separator) - local all=table.sortedkeys(prefixes) - if separator then - for i=1,#all do - all[i]=all[i]..":" - end - end - return all -end -local function _resolve_(method,target) - local action=prefixes[method] - if action then - return action(target) - else - return method..":"..target - end -end -local resolved,abstract={},{} -function resolvers.resetresolve(str) - resolved,abstract={},{} -end -local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) -local prefix=C(R("az")^2)*P(":") -local target=C((1-S(" \"\';,"))^1) -local notarget=(#S(";,")+P(-1))*Cc("") -local pattern=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) -local function resolve(str) - if type(str)=="table" then - local t={} - for i=1,#str do - t[i]=resolve(str[i]) - end - return t - else - local res=resolved[str] - if not res then - res=lpegmatch(pattern,str) - resolved[str]=res - abstract[res]=str - end - return res - end -end -local function unresolve(str) - return abstract[str] or str -end -resolvers.resolve=resolve -resolvers.unresolve=unresolve -if type(os.uname)=="function" then - for k,v in next,os.uname() do - if not prefixes[k] then - prefixes[k]=function() return v end - end - end -end -if os.type=="unix" then - local pattern - local function makepattern(t,k,v) - if t then - rawset(t,k,v) - end - local colon=P(":") - for k,v in table.sortedpairs(prefixes) do - if p then - p=P(k)+p - else - p=P(k) - end - end - pattern=Cs((p*colon+colon/";"+P(1))^0) - end - makepattern() - getmetatable(prefixes).__newindex=makepattern - function resolvers.repath(str) - return lpegmatch(pattern,str) - end -else - function resolvers.repath(str) - return str - end -end end -- of closure @@ -15419,7 +15536,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-fil"] = package.loaded["data-fil"] or true --- original size: 3801, stripped down to: 3231 +-- original size: 3863, stripped down to: 3310 if not modules then modules={} end modules ['data-fil']={ version=1.001, @@ -15431,30 +15548,31 @@ if not modules then modules={} end modules ['data-fil']={ local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_files=logs.reporter("resolvers","files") local resolvers=resolvers +local resolveprefix=resolvers.resolve local finders,openers,loaders,savers=resolvers.finders,resolvers.openers,resolvers.loaders,resolvers.savers local locators,hashers,generators,concatinators=resolvers.locators,resolvers.hashers,resolvers.generators,resolvers.concatinators local checkgarbage=utilities.garbagecollector and utilities.garbagecollector.check function locators.file(specification) - local name=specification.filename - local realname=resolvers.resolve(name) + local filename=specification.filename + local realname=resolveprefix(filename) if realname and realname~='' and lfs.isdir(realname) then if trace_locating then - report_files("file locator %a found as %a",name,realname) + report_files("file locator %a found as %a",filename,realname) end - resolvers.appendhash('file',name,true) + resolvers.appendhash('file',filename,true) elseif trace_locating then - report_files("file locator %a not found",name) + report_files("file locator %a not found",filename) end end function hashers.file(specification) - local name=specification.filename - local content=caches.loadcontent(name,'files') - resolvers.registerfilehash(name,content,content==nil) + local pathname=specification.filename + local content=caches.loadcontent(pathname,'files') + resolvers.registerfilehash(pathname,content,content==nil) end function generators.file(specification) - local path=specification.filename - local content=resolvers.scanfiles(path,false,true) - resolvers.registerfilehash(path,content,true) + local pathname=specification.filename + local content=resolvers.scanfiles(pathname,false,true) + resolvers.registerfilehash(pathname,content,true) end concatinators.file=file.join function finders.file(specification,filetype) @@ -15736,7 +15854,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-zip"] = package.loaded["data-zip"] or true --- original size: 8489, stripped down to: 6757 +-- original size: 9043, stripped down to: 7073 if not modules then modules={} end modules ['data-zip']={ version=1.001, @@ -15779,7 +15897,7 @@ function zip.openarchive(name) local arch=archives[name] if not arch then local full=resolvers.findfile(name) or "" - arch=(full~="" and zip.open(full)) or false + arch=full~="" and zip.open(full) or false archives[name]=arch end return arch @@ -15938,31 +16056,42 @@ function resolvers.usezipfile(archive) end end function resolvers.registerzipfile(z,tree) - local files,filter={},"" - if tree=="" then - filter="^(.+)/(.-)$" - else - filter=format("^%s/(.+)/(.-)$",tree) - end + local names={} + local files={} + local remap={} + local n=0 + local filter=tree=="" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree) + local register=resolvers.registerfile if trace_locating then report_zip("registering: using filter %a",filter) end - local register,n=resolvers.registerfile,0 for i in z:files() do - local path,name=match(i.filename,filter) - if path then - if name and name~='' then - register(files,name,path) - n=n+1 - else + local filename=i.filename + local path,name=match(filename,filter) + if not path then + n=n+1 + register(names,filename,"") + local usedname=lower(filename) + files[usedname]="" + if usedname~=filename then + remap[usedname]=filename end - else - register(files,i.filename,'') + elseif name and name~="" then n=n+1 + register(names,name,path) + local usedname=lower(name) + files[usedname]=path + if usedname~=name then + remap[usedname]=name + end + else end end report_zip("registering: %s files registered",n) - return files + return { + files=files, + remap=remap, + } end @@ -15972,7 +16101,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tre"] = package.loaded["data-tre"] or true --- original size: 2508, stripped down to: 2074 +-- original size: 4859, stripped down to: 3335 if not modules then modules={} end modules ['data-tre']={ version=1.001, @@ -15981,42 +16110,50 @@ if not modules then modules={} end modules ['data-tre']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local find,gsub,format=string.find,string.gsub,string.format +local find,gsub,lower=string.find,string.gsub,string.lower +local basename,dirname,joinname=file.basename,file.dirname,file .join +local globdir,isdir=dir.glob,lfs.isdir local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_trees=logs.reporter("resolvers","trees") local resolvers=resolvers -local done,found,notfound={},{},resolvers.finders.notfound -function resolvers.finders.tree(specification) +local resolveprefix=resolvers.resolve +local notfound=resolvers.finders.notfound +local collectors={} +local found={} +function resolvers.finders.tree(specification) local spec=specification.filename - local fnd=found[spec] - if fnd==nil then + local okay=found[spec] + if okay==nil then if spec~="" then - local path,name=file.dirname(spec),file.basename(spec) - if path=="" then path="." end - local hash=done[path] - if not hash then - local pattern=path.."/*" - hash=dir.glob(pattern) - done[path]=hash + local path=dirname(spec) + local name=basename(spec) + if path=="" then + path="." + end + local names=collectors[path] + if not names then + local pattern=find(path,"/%*+$") and path or (path.."/*") + names=globdir(pattern) + collectors[path]=names end local pattern="/"..gsub(name,"([%.%-%+])","%%%1").."$" - for k=1,#hash do - local v=hash[k] - if find(v,pattern) then - found[spec]=v - return v + for i=1,#names do + local fullname=names[i] + if find(fullname,pattern) then + found[spec]=fullname + return fullname end end end - fnd=notfound() - found[spec]=fnd + okay=notfound() + found[spec]=okay end - return fnd + return okay end function resolvers.locators.tree(specification) local name=specification.filename - local realname=resolvers.resolve(name) - if realname and realname~='' and lfs.isdir(realname) then + local realname=resolveprefix(name) + if realname and realname~='' and isdir(realname) then if trace_locating then report_trees("locator %a found",realname) end @@ -16033,10 +16170,43 @@ function resolvers.hashers.tree(specification) resolvers.methodhandler("hashers",name) resolvers.generators.file(specification) end -resolvers.concatinators.tree=resolvers.concatinators.file -resolvers.generators.tree=resolvers.generators.file -resolvers.openers.tree=resolvers.openers.file -resolvers.loaders.tree=resolvers.loaders.file +local collectors={} +table.setmetatableindex(collectors,function(t,k) + local rootname=gsub(k,"[/%*]+$","") + local dataname=joinname(rootname,"dirlist") + local data=caches.loadcontent(dataname,"files",dataname) + local content=data and data.content + local lookup=resolvers.get_from_content + if not content then + content=resolvers.scanfiles(rootname) + caches.savecontent(dataname,"files",content,dataname) + end + local files=content.files + local v=function(filename) + local path,name=lookup(content,filename) + if not path then + return filename + elseif type(path)=="table" then + path=path[1] + end + return joinname(rootname,path,name) + end + t[k]=v + return v +end) +function resolvers.finders.dirlist(specification) + local spec=specification.filename + if spec~="" then + local path,name=dirname(spec),basename(spec) + return path and collectors[path](name) or notfound() + end + return notfound() +end +resolvers.locators .dirlist=resolvers.locators .tree +resolvers.hashers .dirlist=resolvers.hashers .tree +resolvers.generators.dirlist=resolvers.generators.file +resolvers.openers .dirlist=resolvers.openers .file +resolvers.loaders .dirlist=resolvers.loaders .file end -- of closure @@ -16221,7 +16391,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-lua"] = package.loaded["data-lua"] or true --- original size: 4237, stripped down to: 3177 +-- original size: 4313, stripped down to: 3227 if not modules then modules={} end modules ['data-lua']={ version=1.001, @@ -16230,7 +16400,7 @@ if not modules then modules={} end modules ['data-lua']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local resolvers,package=resolvers,package +local package,lpeg=package,lpeg local gsub=string.gsub local concat=table.concat local addsuffix=file.addsuffix @@ -16241,9 +16411,11 @@ local luaformats={ 'TEXINPUTS','LUAINPUTS' } local libformats={ 'CLUAINPUTS' } local helpers=package.helpers or {} local methods=helpers.methods or {} +local resolvers=resolvers +local resolveprefix=resolvers.resolve +helpers.report=logs.reporter("resolvers","libraries") trackers.register("resolvers.libraries",function(v) helpers.trace=v end) trackers.register("resolvers.locating",function(v) helpers.trace=v end) -helpers.report=logs.reporter("resolvers","libraries") helpers.sequence={ "already loaded", "preload table", @@ -16258,7 +16430,7 @@ helpers.sequence={ } local pattern=Cs(P("!")^0/""*(P("/")*P(-1)/"/"+P("/")^1/"/"+1)^0) function helpers.cleanpath(path) - return resolvers.resolve(lpegmatch(pattern,path)) + return resolveprefix(lpegmatch(pattern,path)) end local loadedaslib=helpers.loadedaslib local getextraluapaths=package.extraluapaths @@ -16395,7 +16567,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tmf"] = package.loaded["data-tmf"] or true --- original size: 2600, stripped down to: 1627 +-- original size: 2601, stripped down to: 1627 if not modules then modules={} end modules ['data-tmf']={ version=1.001, @@ -16451,7 +16623,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-lst"] = package.loaded["data-lst"] or true --- original size: 2654, stripped down to: 2301 +-- original size: 2734, stripped down to: 2354 if not modules then modules={} end modules ['data-lst']={ version=1.001, @@ -16460,10 +16632,13 @@ if not modules then modules={} end modules ['data-lst']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local find,concat,upper,format=string.find,table.concat,string.upper,string.format +local rawget,type,next=rawget,type,next +local find,concat,upper=string.find,table.concat,string.upper local fastcopy,sortedpairs=table.fastcopy,table.sortedpairs -resolvers.listers=resolvers.listers or {} local resolvers=resolvers +local listers=resolvers.listers or {} +resolvers.listers=listers +local resolveprefix=resolvers.resolve local report_lists=logs.reporter("resolvers","lists") local function tabstr(str) if type(str)=='table' then @@ -16472,7 +16647,7 @@ local function tabstr(str) return str end end -function resolvers.listers.variables(pattern) +function listers.variables(pattern) local instance=resolvers.instance local environment=instance.environment local variables=instance.variables @@ -16493,10 +16668,10 @@ function resolvers.listers.variables(pattern) for key,value in sortedpairs(configured) do if key~="" and (pattern=="" or find(upper(key),pattern)) then report_lists(key) - report_lists(" env: %s",tabstr(rawget(environment,key)) or "unset") - report_lists(" var: %s",tabstr(configured[key]) or "unset") - report_lists(" exp: %s",tabstr(expansions[key]) or "unset") - report_lists(" res: %s",tabstr(resolvers.resolve(expansions[key])) or "unset") + report_lists(" env: %s",tabstr(rawget(environment,key)) or "unset") + report_lists(" var: %s",tabstr(configured[key]) or "unset") + report_lists(" exp: %s",tabstr(expansions[key]) or "unset") + report_lists(" res: %s",tabstr(resolveprefix(expansions[key])) or "unset") end end instance.environment=fastcopy(env) @@ -16504,15 +16679,15 @@ function resolvers.listers.variables(pattern) instance.expansions=fastcopy(exp) end local report_resolved=logs.reporter("system","resolved") -function resolvers.listers.configurations() +function listers.configurations() local configurations=resolvers.instance.specification for i=1,#configurations do - report_resolved("file : %s",resolvers.resolve(configurations[i])) + report_resolved("file : %s",resolveprefix(configurations[i])) end report_resolved("") local list=resolvers.expandedpathfromlist(resolvers.splitpath(resolvers.luacnfspec)) for i=1,#list do - local li=resolvers.resolve(list[i]) + local li=resolveprefix(list[i]) if lfs.isdir(li) then report_resolved("path - %s",li) else @@ -16951,8 +17126,8 @@ end -- of closure -- used libraries : l-lua.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-sto.lua util-prs.lua util-fmt.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-mrg.lua util-tpl.lua util-env.lua luat-env.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua util-lib.lua luat-sta.lua luat-fmt.lua -- skipped libraries : - --- original bytes : 699655 --- stripped bytes : 249540 +-- original bytes : 704727 +-- stripped bytes : 250243 -- end library merge diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua index 189fc4b7b..70f493525 100644 --- a/scripts/context/stubs/mswin/mtxrun.lua +++ b/scripts/context/stubs/mswin/mtxrun.lua @@ -1195,7 +1195,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-table"] = package.loaded["l-table"] or true --- original size: 31828, stripped down to: 20814 +-- original size: 33243, stripped down to: 21578 if not modules then modules={} end modules ['l-table']={ version=1.001, @@ -1342,14 +1342,14 @@ local function sortedhash(t,cmp) end local n=0 local m=#s - local function kv(s) + local function kv() if n<m then n=n+1 local k=s[n] return k,t[k] end end - return kv,s + return kv else return nothing end @@ -2110,6 +2110,44 @@ function table.values(t,s) return {} end end +function table.filtered(t,pattern,sort,cmp) + if t and type(pattern)=="string" then + if sort then + local s + if cmp then + s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) + else + s=sortedkeys(t) + end + local n=0 + local m=#s + local function kv(s) + while n<m do + n=n+1 + local k=s[n] + if find(k,pattern) then + return k,t[k] + end + end + end + return kv,s + else + local n=next(t) + local function iterator() + while n do + local k=n + n=next(t,k) + if find(k,pattern) then + return k,t[k] + end + end + end + return iterator,t + end + else + return nothing + end +end end -- of closure @@ -3775,7 +3813,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-dir"] = package.loaded["l-dir"] or true --- original size: 14788, stripped down to: 9096 +-- original size: 16056, stripped down to: 10707 if not modules then modules={} end modules ['l-dir']={ version=1.001, @@ -3785,7 +3823,7 @@ if not modules then modules={} end modules ['l-dir']={ license="see context related readme files" } local type,select=type,select -local find,gmatch,match,gsub=string.find,string.gmatch,string.match,string.gsub +local find,gmatch,match,gsub,sub=string.find,string.gmatch,string.match,string.gsub,string.sub local concat,insert,remove,unpack=table.concat,table.insert,table.remove,table.unpack local lpegmatch=lpeg.match 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 @@ -3794,54 +3832,123 @@ local dir=dir local lfs=lfs local attributes=lfs.attributes local walkdir=lfs.dir -local isdir=lfs.isdir -local isfile=lfs.isfile +local isdir=lfs.isdir +local isfile=lfs.isfile local currentdir=lfs.currentdir local chdir=lfs.chdir local mkdir=lfs.mkdir local onwindows=os.type=="windows" or find(os.getenv("PATH"),";",1,true) -if not isdir then - function isdir(name) - local a=attributes(name) - return a and a.mode=="directory" +if onwindows then + isdir=function(name) + name=gsub(name,"([/\\]+)$","/.") + return attributes(name,"mode")=="directory" + end + isfile=function(name) + return attributes(name,"mode")=="file" end lfs.isdir=isdir -end -if not isfile then - function isfile(name) - local a=attributes(name) - return a and a.mode=="file" + lfs.isfile=isfile +else + isdir=function(name) + return attributes(name,"mode")=="directory" + end + isfile=function(name) + return attributes(name,"mode")=="file" end + lfs.isdir=isdir lfs.isfile=isfile end function dir.current() return (gsub(currentdir(),"\\","/")) end -local lfsisdir=isdir -local function isdir(path) - path=gsub(path,"[/\\]+$","") - return lfsisdir(path) +local function glob_pattern_function(path,patt,recurse,action) + if isdir(path) then + local usedpath + if path=="/" then + usedpath="/." + elseif not find(path,"/$") then + usedpath=path.."/." + path=path.."/" + else + usedpath=path + end + local dirs + for name in walkdir(usedpath) do + if name~="." and name~=".." then + local full=path..name + local mode=attributes(full,'mode') + if mode=='file' then + if not patt or find(full,patt) then + action(full) + end + elseif recurse and mode=="directory" then + if not dirs then + dirs={ full } + else + dirs[#dirs+1]=full + end + end + end + end + if dirs then + for i=1,#dirs do + glob_pattern_function(dirs[i],patt,recurse,action) + end + end + end end -lfs.isdir=isdir -local function globpattern(path,patt,recurse,action) - if path=="/" then - path=path.."." - elseif not find(path,"/$") then - path=path..'/' - end - if isdir(path) then - for name in walkdir(path) do - local full=path..name - local mode=attributes(full,'mode') - if mode=='file' then - if find(full,patt) then - action(full) +local function glob_pattern_table(path,patt,recurse,result) + if not result then + result={} + end + if isdir(path) then + local usedpath + if path=="/" then + usedpath="/." + elseif not find(path,"/$") then + usedpath=path.."/." + path=path.."/" + else + usedpath=path + end + local dirs + for name in walkdir(usedpath) do + if name~="." and name~=".." then + local full=path..name + local mode=attributes(full,'mode') + if mode=='file' then + if not patt or find(full,patt) then + result[#result+1]=full + end + elseif recurse and mode=="directory" then + if not dirs then + dirs={ full } + else + dirs[#dirs+1]=full + end end - elseif recurse and (mode=="directory") and (name~='.') and (name~="..") then - globpattern(full,patt,recurse,action) + end + end + if dirs then + for i=1,#dirs do + glob_pattern_table(dirs[i],patt,recurse,result) end end end + return result +end +local function globpattern(path,patt,recurse,method) + local kind=type(method) + if pattern and sub(patt,1,-3)==path then + patt=false + end + if kind=="function" then + return glob_pattern_function(path,patt,recurse,method) + elseif kind=="table" then + return glob_pattern_table(path,patt,recurse,method) + else + return glob_pattern_table(path,patt,recurse,{}) + end end dir.globpattern=globpattern local function collectpattern(path,patt,recurse,result) @@ -3853,18 +3960,24 @@ local function collectpattern(path,patt,recurse,result) ok,scanner,first=xpcall(function() return walkdir(path) end,function() end) end if ok and type(scanner)=="function" then - if not find(path,"/$") then path=path..'/' end + if not find(path,"/$") then + path=path..'/' + end for name in scanner,first do - local full=path..name - local attr=attributes(full) - local mode=attr.mode - if mode=='file' then - if find(full,patt) then + if name=="." then + elseif name==".." then + else + 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" then + attr.list=collectpattern(full,patt,recurse) result[name]=attr end - elseif recurse and (mode=="directory") and (name~='.') and (name~="..") then - attr.list=collectpattern(full,patt,recurse) - result[name]=attr end end end @@ -3872,15 +3985,15 @@ local function collectpattern(path,patt,recurse,result) end dir.collectpattern=collectpattern local separator -if onwindows then +if onwindows then local slash=S("/\\")/"/" - pattern=Ct { + pattern={ [1]=(Cs(P(".")+slash^1)+Cs(R("az","AZ")*P(":")*slash^0)+Cc("./"))*V(2)*V(3), [2]=Cs(((1-S("*?/\\"))^0*slash)^0), [3]=Cs(P(1)^0) } -else - pattern=Ct { +else + pattern={ [1]=(C(P(".")+P("/")^1)+Cc("./"))*V(2)*V(3), [2]=C(((1-S("*?/"))^0*P("/"))^0), [3]=C(P(1)^0) @@ -3898,9 +4011,8 @@ local function glob(str,t) elseif 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 root,path,base=lpegmatch(pattern,str) + if root and path and base then local recurse=find(base,"**",1,true) local start=root..path local result=lpegmatch(filter,start..base) @@ -3922,16 +4034,12 @@ local function glob(str,t) return { str } end 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 root,path,base=lpegmatch(pattern,str) + if root and path and base then local recurse=find(base,"**",1,true) local start=root..path local result=lpegmatch(filter,start..base) - globpattern(start,result,recurse,action) - return t + return globpattern(start,result,recurse,t) else return {} end @@ -4879,7 +4987,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-str"] = package.loaded["util-str"] or true --- original size: 33485, stripped down to: 18420 +-- original size: 34240, stripped down to: 18733 if not modules then modules={} end modules ['util-str']={ version=1.001, @@ -5544,6 +5652,15 @@ else add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=lpeg.patterns.texescape }) add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=lpeg.patterns.luaescape }) end +local dquote=patterns.dquote +local equote=patterns.escaped+dquote/'\\"'+1 +local space=patterns.space +local cquote=Cc('"') +local pattern=Cs(dquote*(equote-P(-2))^0*dquote) ++Cs(cquote*(equote-space)^0*space*equote^0*cquote) +function string.optionalquoted(str) + return lpegmatch(pattern,str) or str +end end -- of closure @@ -8717,7 +8834,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-env"] = package.loaded["util-env"] or true --- original size: 8814, stripped down to: 5092 +-- original size: 8022, stripped down to: 5038 if not modules then modules={} end modules ['util-env']={ version=1.001, @@ -8728,7 +8845,7 @@ if not modules then modules={} end modules ['util-env']={ } local allocate,mark=utilities.storage.allocate,utilities.storage.mark local format,sub,match,gsub,find=string.format,string.sub,string.match,string.gsub,string.find -local unquoted,quoted=string.unquoted,string.quoted +local unquoted,quoted,optionalquoted=string.unquoted,string.quoted,string.optionalquoted local concat,insert,remove=table.concat,table.insert,table.remove environment=environment or {} local environment=environment @@ -8841,24 +8958,14 @@ function environment.splitarguments(separator) return before,after end function environment.reconstructcommandline(arg,noquote) + local resolveprefix=resolvers.resolve arg=arg or environment.originalarguments if noquote and #arg==1 then - local a=arg[1] - a=resolvers.resolve(a) - a=unquoted(a) - return a + return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1]) elseif #arg>0 then local result={} for i=1,#arg do - local a=arg[i] - a=resolvers.resolve(a) - a=unquoted(a) - a=gsub(a,'"','\\"') - if find(a," ",1,true) then - result[#result+1]=quoted(a) - else - result[#result+1]=a - end + result[i]=optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix) end return concat(result," ") else @@ -12483,7 +12590,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-ini"] = package.loaded["data-ini"] or true --- original size: 7927, stripped down to: 5528 +-- original size: 10598, stripped down to: 7341 if not modules then modules={} end modules ['data-ini']={ version=1.001, @@ -12492,14 +12599,15 @@ if not modules then modules={} end modules ['data-ini']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files", } +local next,type,getmetatable,rawset=next,type,getmetatable,rawset local gsub,find,gmatch,char=string.gsub,string.find,string.gmatch,string.char -local next,type=next,type local filedirname,filebasename,filejoin=file.dirname,file.basename,file.join +local ostype,osname,osuname,ossetenv,osgetenv=os.type,os.name,os.uname,os.setenv,os.getenv +local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local trace_detail=false trackers.register("resolvers.details",function(v) trace_detail=v end) local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) local report_initialization=logs.reporter("resolvers","initialization") -local ostype,osname,ossetenv,osgetenv=os.type,os.name,os.setenv,os.getenv resolvers=resolvers or {} local resolvers=resolvers texconfig.kpse_init=false @@ -12632,10 +12740,88 @@ if type(profiler)=="table" and not jit then profiler.start("luatex-profile.log") end) end -if not resolvers.resolve then - function resolvers.resolve (s) return s end - function resolvers.unresolve(s) return s end - function resolvers.repath (s) return s end +local prefixes=utilities.storage.allocate() +resolvers.prefixes=prefixes +local resolved={} +local abstract={} +function resolvers.resetresolve(str) + resolved,abstract={},{} +end +function resolvers.allprefixes(separator) + local all=table.sortedkeys(prefixes) + if separator then + for i=1,#all do + all[i]=all[i]..":" + end + end + return all +end +local function _resolve_(method,target) + local action=prefixes[method] + if action then + return action(target) + else + return method..":"..target + end +end +function resolvers.unresolve(str) + return abstract[str] or str +end +local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) +local prefix=C(R("az")^2)*P(":") +local target=C((1-S(" \"\';,"))^1) +local notarget=(#S(";,")+P(-1))*Cc("") +local pattern=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) +local function resolve(str) + if type(str)=="table" then + local res={} + for i=1,#str do + res[i]=resolve(str[i]) + end + return res + else + local res=resolved[str] + if not res then + res=lpegmatch(pattern,str) + resolved[str]=res + abstract[res]=str + end + return res + end +end +resolvers.resolve=resolve +if type(osuname)=="function" then + for k,v in next,osuname() do + if not prefixes[k] then + prefixes[k]=function() return v end + end + end +end +if ostype=="unix" then + local pattern + local function makepattern(t,k,v) + if t then + rawset(t,k,v) + end + local colon=P(":") + for k,v in table.sortedpairs(prefixes) do + if p then + p=P(k)+p + else + p=P(k) + end + end + pattern=Cs((p*colon+colon/";"+P(1))^0) + end + makepattern() + table.setmetatablenewindex(prefixes,makepattern) + function resolvers.repath(str) + return lpegmatch(pattern,str) + end +else + function resolvers.repath(str) + return str + end end @@ -12645,7 +12831,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-exp"] = package.loaded["data-exp"] or true --- original size: 15317, stripped down to: 9723 +-- original size: 16463, stripped down to: 10113 if not modules then modules={} end modules ['data-exp']={ version=1.001, @@ -12660,11 +12846,14 @@ local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns local Ct,Cs,Cc,Carg,P,C,S=lpeg.Ct,lpeg.Cs,lpeg.Cc,lpeg.Carg,lpeg.P,lpeg.C,lpeg.S local type,next=type,next local ostype=os.type -local collapsepath=file.collapsepath +local collapsepath,joinpath,basename=file.collapsepath,file.join,file.basename local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_globbing=true trackers.register("resolvers.globbing",function(v) trace_globbing=v end) local report_expansions=logs.reporter("resolvers","expansions") +local report_globbing=logs.reporter("resolvers","globbing") local resolvers=resolvers +local resolveprefix=resolvers.resolve local function f_both(a,b) local t,n={},0 for sb in gmatch(b,"[^,]+") do @@ -12754,35 +12943,27 @@ function resolvers.expandedpathfromlist(pathlist) end return newlist end -local cleanup=lpeg.replacer { - { "!","" }, - { "\\","/" }, -} -function resolvers.cleanpath(str) - local doslashes=(P("\\")/"/"+1)^0 - local donegation=(P("!")/"" )^0 - local homedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") - if homedir=="~" or homedir=="" or not lfs.isdir(homedir) then - if trace_expansions then - report_expansions("no home dir set, ignoring dependent paths") - end - function resolvers.cleanpath(str) - if not str or find(str,"~",1,true) then - return "" - else - return lpegmatch(cleanup,str) +local usedhomedir=nil +local donegation=(P("!")/"" )^0 +local doslashes=(P("\\")/"/"+1)^0 +local function expandedhome() + if not usedhomedir then + usedhomedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") + if usedhomedir=="~" or usedhomedir=="" or not lfs.isdir(usedhomedir) then + if trace_expansions then + report_expansions("no home dir set, ignoring dependent path using current path") end - end - else - local dohome=((P("~")+P("$HOME"))/homedir)^0 - local cleanup=Cs(donegation*dohome*doslashes) - function resolvers.cleanpath(str) - return str and lpegmatch(cleanup,str) or "" + usedhomedir="." end end - return resolvers.cleanpath(str) + return usedhomedir +end +local dohome=((P("~")+P("$HOME")+P("%HOME%"))/expandedhome)^0 +local cleanup=Cs(donegation*dohome*doslashes) +resolvers.cleanpath=function(str) + return str and lpegmatch(cleanup,str) or "" end -local expandhome=P("~")/"$HOME" +local expandhome=P("~")/"$HOME" local dodouble=P('"')/""*(expandhome+(1-P('"')))^0*P('"')/"" local dosingle=P("'")/""*(expandhome+(1-P("'")))^0*P("'")/"" local dostring=(expandhome+1 )^0 @@ -12834,7 +13015,7 @@ function resolvers.splitpath(str) end function resolvers.joinpath(str) if type(str)=='table' then - return file.joinpath(str) + return joinpath(str) else return str end @@ -12845,35 +13026,54 @@ local timer={} local scanned={} local nofscans=0 local scancache={} -local function scan(files,spec,path,n,m,r) - local full=(path=="" and spec) or (spec..path..'/') +local fullcache={} +local nofsharedscans=0 +local function scan(files,remap,spec,path,n,m,r,onlyone) + local full=path=="" and spec or (spec..path..'/') local dirs={} local nofdirs=0 for name in directory(full) do if not lpegmatch(weird,name) then - local mode=attributes(full..name,'mode') - if mode=='file' then + local mode=attributes(full..name,"mode") + if mode=="file" then n=n+1 - local f=files[name] - if f then - if type(f)=='string' then - files[name]={ f,path } + local lower=lower(name) + local paths=files[lower] + if paths then + if onlyone then else - f[#f+1]=path + if type(paths)=="string" then + files[lower]={ paths,path } + else + paths[#paths+1]=path + end + if name~=lower then + local rl=remap[lower] + if not rl then + remap[lower]=name + r=r+1 + elseif trace_globbing and rl~=name then + report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) + end + end end else - files[name]=path - local lower=lower(name) + files[lower]=path if name~=lower then - files["remap:"..lower]=name - r=r+1 + local rl=remap[lower] + if not rl then + remap[lower]=name + r=r+1 + elseif trace_globbing and rl~=name then + report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) + end end end - elseif mode=='directory' then + elseif mode=="directory" then m=m+1 nofdirs=nofdirs+1 if path~="" then - dirs[nofdirs]=path..'/'..name + dirs[nofdirs]=path.."/"..name else dirs[nofdirs]=name end @@ -12883,107 +13083,52 @@ local function scan(files,spec,path,n,m,r) if nofdirs>0 then sort(dirs) for i=1,nofdirs do - files,n,m,r=scan(files,spec,dirs[i],n,m,r) + files,remap,n,m,r=scan(files,remap,spec,dirs[i],n,m,r,onlyone) end end scancache[sub(full,1,-2)]=files - return files,n,m,r + return files,remap,n,m,r end -local fullcache={} -function resolvers.scanfiles(path,branch,usecache) - statistics.starttiming(timer) - local realpath=resolvers.resolve(path) +function resolvers.scanfiles(path,branch,usecache,onlyonce) + local realpath=resolveprefix(path) if usecache then - local files=fullcache[realpath] - if files then + local content=fullcache[realpath] + if content then if trace_locating then - report_expansions("using caches scan of path %a, branch %a",path,branch or path) + report_expansions("using cached scan of path %a, branch %a",path,branch or path) end - return files + nofsharedscans=nofsharedscans+1 + return content end end + statistics.starttiming(timer) if trace_locating then report_expansions("scanning path %a, branch %a",path,branch or path) end - local files,n,m,r=scan({},realpath..'/',"",0,0,0) - files.__path__=path - files.__files__=n - files.__directories__=m - files.__remappings__=r + local files,remap,n,m,r=scan({},{},realpath..'/',"",0,0,0,onlyonce) + local content={ + metadata={ + path=path, + files=n, + directories=m, + remappings=r, + }, + files=files, + remap=remap, + } if trace_locating then report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r) end if usecache then scanned[#scanned+1]=realpath - fullcache[realpath]=files + fullcache[realpath]=content end nofscans=nofscans+1 statistics.stoptiming(timer) - return files -end -local function simplescan(files,spec,path) - local full=(path=="" and spec) or (spec..path..'/') - local dirs={} - local nofdirs=0 - for name in directory(full) do - if not lpegmatch(weird,name) then - local mode=attributes(full..name,'mode') - if mode=='file' then - if not files[name] then - files[name]=path - end - elseif mode=='directory' then - nofdirs=nofdirs+1 - if path~="" then - dirs[nofdirs]=path..'/'..name - else - dirs[nofdirs]=name - end - end - end - end - if nofdirs>0 then - sort(dirs) - for i=1,nofdirs do - files=simplescan(files,spec,dirs[i]) - end - end - return files + return content end -local simplecache={} -local nofsharedscans=0 function resolvers.simplescanfiles(path,branch,usecache) - statistics.starttiming(timer) - local realpath=resolvers.resolve(path) - if usecache then - local files=simplecache[realpath] - if not files then - files=scancache[realpath] - if files then - nofsharedscans=nofsharedscans+1 - end - end - if files then - if trace_locating then - report_expansions("using caches scan of path %a, branch %a",path,branch or path) - end - return files - end - end - if trace_locating then - report_expansions("scanning path %a, branch %a",path,branch or path) - end - local files=simplescan({},realpath..'/',"") - if trace_locating then - report_expansions("%s files found",table.count(files)) - end - if usecache then - scanned[#scanned+1]=realpath - simplecache[realpath]=files - end - nofscans=nofscans+1 - statistics.stoptiming(timer) - return files + return resolvers.scanfiles(path,branch,usecache,true) end function resolvers.scandata() table.sort(scanned) @@ -12994,6 +13139,49 @@ function resolvers.scandata() paths=scanned, } end +function resolvers.get_from_content(content,path,name) + local files=content.files + if not files then + return + end + local remap=content.remap + if not remap then + return + end + if name then + local used=lower(name) + return path,remap[used] or used + else + local name=path + local used=lower(name) + local path=files[used] + if path then + return path,remap[used] or used + end + end +end +local nothing=function() end +function resolvers.filtered_from_content(content,pattern) + if content and type(pattern)=="string" then + local pattern=lower(pattern) + local files=content.files + local remap=content.remap + if files and remap then + local n=next(files) + local function iterator() + while n do + local k=n + n=next(files,k) + if find(k,pattern) then + return files[k],remap and remap[k] or k + end + end + end + return iterator + end + end + return nothing +end end -- of closure @@ -13272,7 +13460,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tmp"] = package.loaded["data-tmp"] or true --- original size: 15532, stripped down to: 11648 +-- original size: 15681, stripped down to: 11761 if not modules then modules={} end modules ['data-tmp']={ version=1.100, @@ -13291,6 +13479,7 @@ local trace_cache=false trackers.register("resolvers.cache",function(v) trace_ca local report_caches=logs.reporter("resolvers","caches") local report_resolvers=logs.reporter("resolvers","caching") local resolvers=resolvers +local cleanpath=resolvers.cleanpath local directive_cleanup=false directives.register("system.compile.cleanup",function(v) directive_cleanup=v end) local directive_strip=false directives.register("system.compile.strip",function(v) directive_strip=v end) local compile=utilities.lua.compile @@ -13312,7 +13501,7 @@ caches.relocate=false caches.defaults={ "TMPDIR","TEMPDIR","TMP","TEMP","HOME","HOMEPATH" } local writable,readables,usedreadables=nil,{},{} local function identify() - local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") + local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") if texmfcaches then for k=1,#texmfcaches do local cachepath=texmfcaches[k] @@ -13566,10 +13755,12 @@ local content_state={} function caches.contentstate() return content_state or {} end -function caches.loadcontent(cachename,dataname) - local name=caches.hashed(cachename) - local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") - local filename=file.join(path,name) +function caches.loadcontent(cachename,dataname,filename) + if not filename then + local name=caches.hashed(cachename) + local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") + filename=file.join(path,name) + end local blob=loadfile(addsuffix(filename,luasuffixes.luc)) or loadfile(addsuffix(filename,luasuffixes.lua)) if blob then local data=blob() @@ -13601,10 +13792,12 @@ function caches.collapsecontent(content) end end end -function caches.savecontent(cachename,dataname,content) - local name=caches.hashed(cachename) - local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") - local filename=file.join(path,name) +function caches.savecontent(cachename,dataname,content,filename) + if not filename then + local name=caches.hashed(cachename) + local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") + filename=file.join(path,name) + end local luaname=addsuffix(filename,luasuffixes.lua) local lucname=addsuffix(filename,luasuffixes.luc) if trace_locating then @@ -13647,7 +13840,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-met"] = package.loaded["data-met"] or true --- original size: 5460, stripped down to: 4014 +-- original size: 5347, stripped down to: 4015 if not modules then modules={} end modules ['data-met']={ version=1.100, @@ -13675,7 +13868,7 @@ local function splitmethod(filename) if type(filename)=="table" then return filename end - filename=file.collapsepath(filename,".") + filename=file.collapsepath(filename,".") if not find(filename,"://",1,true) then return { scheme="file",path=filename,original=filename,filename=filename } end @@ -13766,7 +13959,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-res"] = package.loaded["data-res"] or true --- original size: 62045, stripped down to: 43116 +-- original size: 61031, stripped down to: 42613 if not modules then modules={} end modules ['data-res']={ version=1.001, @@ -13776,7 +13969,7 @@ if not modules then modules={} end modules ['data-res']={ license="see context related readme files", } local gsub,find,lower,upper,match,gmatch=string.gsub,string.find,string.lower,string.upper,string.match,string.gmatch -local concat,insert,sortedkeys=table.concat,table.insert,table.sortedkeys +local concat,insert,sortedkeys,sortedhash=table.concat,table.insert,table.sortedkeys,table.sortedhash local next,type,rawget=next,type,rawget local os=os local P,S,R,C,Cc,Cs,Ct,Carg=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cc,lpeg.Cs,lpeg.Ct,lpeg.Carg @@ -13785,14 +13978,19 @@ local formatters=string.formatters local filedirname=file.dirname local filebasename=file.basename local suffixonly=file.suffixonly +local addsuffix=file.addsuffix +local removesuffix=file.removesuffix local filejoin=file.join local collapsepath=file.collapsepath local joinpath=file.joinpath +local is_qualified_path=file.is_qualified_path local allocate=utilities.storage.allocate local settings_to_array=utilities.parsers.settings_to_array +local getcurrentdir=lfs.currentdir +local isfile=lfs.isfile +local isdir=lfs.isdir local setmetatableindex=table.setmetatableindex local luasuffixes=utilities.lua.suffixes -local getcurrentdir=lfs.currentdir local trace_locating=false trackers .register("resolvers.locating",function(v) trace_locating=v end) local trace_detail=false trackers .register("resolvers.details",function(v) trace_detail=v end) local trace_expansions=false trackers .register("resolvers.expansions",function(v) trace_expansions=v end) @@ -13803,10 +14001,14 @@ local expandedpathfromlist=resolvers.expandedpathfromlist local checkedvariable=resolvers.checkedvariable local splitconfigurationpath=resolvers.splitconfigurationpath local methodhandler=resolvers.methodhandler +local filtered=resolvers.filtered_from_content +local lookup=resolvers.get_from_content +local cleanpath=resolvers.cleanpath +local resolveprefix=resolvers.resolve local initializesetter=utilities.setters.initialize local ostype,osname,osenv,ossetenv,osgetenv=os.type,os.name,os.env,os.setenv,os.getenv -resolvers.cacheversion='1.0.1' -resolvers.configbanner='' +resolvers.cacheversion="1.100" +resolvers.configbanner="" resolvers.homedir=environment.homedir resolvers.criticalvars=allocate { "SELFAUTOLOC","SELFAUTODIR","SELFAUTOPARENT","TEXMFCNF","TEXMF","TEXOS" } resolvers.luacnfname="texmfcnf.lua" @@ -13833,7 +14035,7 @@ local instance=resolvers.instance or nil function resolvers.setenv(key,value,raw) if instance then instance.environment[key]=value - ossetenv(key,raw and value or resolvers.resolve(value)) + ossetenv(key,raw and value or resolveprefix(value)) end end local function getenv(key) @@ -13847,7 +14049,7 @@ local function getenv(key) end resolvers.getenv=getenv resolvers.env=getenv -local function resolve(k) +local function resolvevariable(k) return instance.expansions[k] end local dollarstripper=lpeg.stripper("$") @@ -13856,19 +14058,19 @@ local backslashswapper=lpeg.replacer("\\","/") local somevariable=P("$")/"" local somekey=C(R("az","AZ","09","__","--")^1) local somethingelse=P(";")*((1-S("!{}/\\"))^1*P(";")/"")+P(";")*(P(";")/"")+P(1) -local variableexpander=Cs((somevariable*(somekey/resolve)+somethingelse)^1 ) +local variableexpander=Cs((somevariable*(somekey/resolvevariable)+somethingelse)^1 ) local cleaner=P("\\")/"/"+P(";")*S("!{}/\\")^0*P(";")^1/";" local variablecleaner=Cs((cleaner+P(1))^0) -local somevariable=R("az","AZ","09","__","--")^1/resolve +local somevariable=R("az","AZ","09","__","--")^1/resolvevariable local variable=(P("$")/"")*(somevariable+(P("{")/"")*somevariable*(P("}")/"")) local variableresolver=Cs((variable+P(1))^0) local function expandedvariable(var) return lpegmatch(variableexpander,var) or var end -function resolvers.newinstance() - if trace_locating then +function resolvers.newinstance() + if trace_locating then report_resolving("creating instance") - end + end local environment,variables,expansions,order=allocate(),allocate(),allocate(),allocate() local newinstance={ environment=environment, @@ -13995,13 +14197,13 @@ local function identify_configuration_files() for i=1,#cnfpaths do local filepath=cnfpaths[i] local filename=collapsepath(filejoin(filepath,luacnfname)) - local realname=resolvers.resolve(filename) + local realname=resolveprefix(filename) if trace_locating then - local fullpath=gsub(resolvers.resolve(collapsepath(filepath)),"//","/") + local fullpath=gsub(resolveprefix(collapsepath(filepath)),"//","/") local weirdpath=find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c",1,true) report_resolving("looking for %a on %s path %a from specification %a",luacnfname,weirdpath and "weird" or "given",fullpath,filepath) end - if lfs.isfile(realname) then + if isfile(realname) then specification[#specification+1]=filename if trace_locating then report_resolving("found configuration file %a",realname) @@ -14023,7 +14225,7 @@ local function load_configuration_files() local filename=specification[i] local pathname=filedirname(filename) local filename=filejoin(pathname,luacnfname) - local realname=resolvers.resolve(filename) + local realname=resolveprefix(filename) local blob=loadfile(realname) if blob then local setups=instance.setups @@ -14031,7 +14233,7 @@ local function load_configuration_files() local parent=data and data.parent if parent then local filename=filejoin(pathname,parent) - local realname=resolvers.resolve(filename) + local realname=resolveprefix(filename) local blob=loadfile(realname) if blob then local parentdata=blob() @@ -14056,7 +14258,7 @@ local function load_configuration_files() elseif variables[k]==nil then if trace_locating and not warning then report_resolving("variables like %a in configuration file %a should move to the 'variables' subtable", - k,resolvers.resolve(filename)) + k,resolveprefix(filename)) warning=true end variables[k]=v @@ -14116,7 +14318,7 @@ local function locate_file_databases() local stripped=lpegmatch(inhibitstripper,path) if stripped~="" then local runtime=stripped==path - path=resolvers.cleanpath(path) + path=cleanpath(path) local spec=resolvers.splitmethod(stripped) if runtime and (spec.noscheme or spec.scheme=="file") then stripped="tree:///"..stripped @@ -14179,8 +14381,8 @@ function resolvers.renew(hashname) report_resolving("identifying tree %a",hashname) end end - local realpath=resolvers.resolve(hashname) - if lfs.isdir(realpath) then + local realpath=resolveprefix(hashname) + if isdir(realpath) then if trace_locating then report_resolving("using path %a",realpath) end @@ -14308,7 +14510,7 @@ function resolvers.registerextrapath(paths,subpaths) local ps=p.."/"..s if not done[ps] then newn=newn+1 - ep[newn]=resolvers.cleanpath(ps) + ep[newn]=cleanpath(ps) done[ps]=true end end @@ -14318,7 +14520,7 @@ function resolvers.registerextrapath(paths,subpaths) local p=paths[i] if not done[p] then newn=newn+1 - ep[newn]=resolvers.cleanpath(p) + ep[newn]=cleanpath(p) done[p]=true end end @@ -14330,7 +14532,7 @@ function resolvers.registerextrapath(paths,subpaths) local ps=ep[i].."/"..s if not done[ps] then newn=newn+1 - ep[newn]=resolvers.cleanpath(ps) + ep[newn]=cleanpath(ps) done[ps]=true end end @@ -14384,7 +14586,7 @@ function resolvers.cleanpathlist(str) local t=resolvers.expandedpathlist(str) if t then for i=1,#t do - t[i]=collapsepath(resolvers.cleanpath(t[i])) + t[i]=collapsepath(cleanpath(t[i])) end end return t @@ -14434,7 +14636,7 @@ function resolvers.registerfilehash(name,content,someerror) end end local function isreadable(name) - local readable=lfs.isfile(name) + local readable=isfile(name) if trace_detail then if readable then report_resolving("file %a is readable",name) @@ -14445,69 +14647,56 @@ local function isreadable(name) return readable end local function collect_files(names) - local filelist,noffiles={},0 + local filelist={} + local noffiles=0 + local function check(hash,root,pathname,path,name) + if not pathname or find(path,pathname) then + local variant=hash.type + local search=filejoin(root,path,name) + local result=methodhandler('concatinators',variant,root,path,name) + if trace_detail then + report_resolving("match: variant %a, search %a, result %a",variant,search,result) + end + noffiles=noffiles+1 + filelist[noffiles]={ variant,search,result } + end + end for k=1,#names do - local fname=names[k] + local filename=names[k] if trace_detail then - report_resolving("checking name %a",fname) + report_resolving("checking name %a",filename) end - local bname=filebasename(fname) - local dname=filedirname(fname) - if dname=="" or find(dname,"^%.") then - dname=false + local basename=filebasename(filename) + local pathname=filedirname(filename) + if pathname=="" or find(pathname,"^%.") then + pathname=false else - dname=gsub(dname,"%*",".*") - dname="/"..dname.."$" + pathname=gsub(pathname,"%*",".*") + pathname="/"..pathname.."$" end local hashes=instance.hashes for h=1,#hashes do local hash=hashes[h] - local blobpath=hash.name - local files=blobpath and instance.files[blobpath] - if files then + local hashname=hash.name + local content=hashname and instance.files[hashname] + if content then if trace_detail then - report_resolving("deep checking %a, base %a, pattern %a",blobpath,bname,dname) - 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 + report_resolving("deep checking %a, base %a, pattern %a",blobpath,basename,pathname) end - if blobfile then - local blobroot=files.__path__ or blobpath - if type(blobfile)=='string' then - if not dname or find(blobfile,dname) then - local variant=hash.type - local search=filejoin(blobroot,blobfile,bname) - local result=methodhandler('concatinators',hash.type,blobroot,blobfile,bname) - if trace_detail then - report_resolving("match: variant %a, search %a, result %a",variant,search,result) - end - noffiles=noffiles+1 - filelist[noffiles]={ variant,search,result } - end + local path,name=lookup(content,basename) + if path then + local metadata=content.metadata + local realroot=metadata and metadata.path or hashname + if type(path)=="string" then + check(hash,realroot,pathname,path,name) else - for kk=1,#blobfile do - local vv=blobfile[kk] - if not dname or find(vv,dname) then - local variant=hash.type - local search=filejoin(blobroot,vv,bname) - local result=methodhandler('concatinators',hash.type,blobroot,vv,bname) - if trace_detail then - report_resolving("match: variant %a, search %a, result %a",variant,search,result) - end - noffiles=noffiles+1 - filelist[noffiles]={ variant,search,result } - end + for i=1,#path do + check(hash,realroot,pathname,path[i],name) end end end elseif trace_locating then - report_resolving("no match in %a (%s)",blobpath,bname) + report_resolving("no match in %a (%s)",hashname,basename) end end end @@ -14532,7 +14721,7 @@ end local function can_be_dir(name) local fakepaths=instance.fakepaths if not fakepaths[name] then - if lfs.isdir(name) then + if isdir(name) then fakepaths[name]=1 else fakepaths[name]=2 @@ -14548,10 +14737,11 @@ local function find_analyze(filename,askedformat,allresults) if askedformat=="" then if ext=="" or not suffixmap[ext] then local defaultsuffixes=resolvers.defaultsuffixes + local formatofsuffix=resolvers.formatofsuffix for i=1,#defaultsuffixes do local forcedname=filename..'.'..defaultsuffixes[i] wantedfiles[#wantedfiles+1]=forcedname - filetype=resolvers.formatofsuffix(forcedname) + filetype=formatofsuffix(forcedname) if trace_locating then report_resolving("forcing filetype %a",filetype) end @@ -14591,14 +14781,14 @@ local function find_wildcard(filename,allresults) if trace_locating then report_resolving("checking wildcard %a",filename) end - local method,result=resolvers.findwildcardfiles(filename) + local result=resolvers.findwildcardfiles(filename) if result then return "wildcard",result end end end local function find_qualified(filename,allresults,askedformat,alsostripped) - if not file.is_qualified_path(filename) then + if not is_qualified_path(filename) then return end if trace_locating then @@ -14687,7 +14877,6 @@ local function find_intree(filename,filetype,wantedfiles,allresults) if trace_detail then report_resolving("checking filename %a",filename) end - local resolve=resolvers.resolve local result={} for k=1,#pathlist do local path=pathlist[k] @@ -14706,8 +14895,8 @@ local function find_intree(filename,filetype,wantedfiles,allresults) local fl=filelist[k] local f=fl[2] local d=dirlist[k] - if find(d,expression) or find(resolve(d),expression) then - result[#result+1]=resolve(fl[3]) + if find(d,expression) or find(resolveprefix(d),expression) then + result[#result+1]=resolveprefix(fl[3]) done=true if allresults then if trace_detail then @@ -14729,7 +14918,7 @@ local function find_intree(filename,filetype,wantedfiles,allresults) else method="filesystem" pathname=gsub(pathname,"/+$","") - pathname=resolve(pathname) + pathname=resolveprefix(pathname) local scheme=url.hasscheme(pathname) if not scheme or scheme=="file" then local pname=gsub(pathname,"%.%*$",'') @@ -14819,7 +15008,7 @@ local function find_otherwise(filename,filetype,wantedfiles,allresults) local filelist=collect_files(wantedfiles) local fl=filelist and filelist[1] if fl then - return "otherwise",{ resolvers.resolve(fl[3]) } + return "otherwise",{ resolveprefix(fl[3]) } end end collect_instance_files=function(filename,askedformat,allresults) @@ -14919,39 +15108,30 @@ function resolvers.findpath(filename,filetype) return filedirname(findfiles(filename,filetype,false)[1] or "") end local function findgivenfiles(filename,allresults) - local bname,result=filebasename(filename),{} + local base=filebasename(filename) + local result={} local hashes=instance.hashes - local noffound=0 + local function okay(hash,path,name) + local found=methodhandler('concatinators',hash.type,hash.name,path,name) + if found and found~="" then + result[#result+1]=resolveprefix(found) + return not allresults + end + end for k=1,#hashes do local hash=hashes[k] - local files=instance.files[hash.name] 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 - local found=methodhandler('concatinators',hash.type,hash.name,blist,bname) or "" - if found~="" then - noffound=noffound+1 - result[noffound]=resolvers.resolve(found) - if not allresults then - break - end + local content=instance.files[hash.name] + if content then + local path,name=lookup(content,base) + if not path then + elseif type(path)=="string" then + if okay(hash,path,name) then + return result end else - for kk=1,#blist do - local vv=blist[kk] - local found=methodhandler('concatinators',hash.type,hash.name,vv,bname) or "" - if found~="" then - noffound=noffound+1 - result[noffound]=resolvers.resolve(found) - if not allresults then break end + for i=1,#path do + if okay(hash,path[i],name) then + return result end end end @@ -14965,64 +15145,80 @@ end function resolvers.findgivenfile(filename) return findgivenfiles(filename,false)[1] or "" end -local function doit(path,blist,bname,tag,variant,result,allresults) - local done=false - if blist and variant then - local resolve=resolvers.resolve - if type(blist)=='string' then - if find(lower(blist),path) then - local full=methodhandler('concatinators',variant,tag,blist,bname) or "" - result[#result+1]=resolve(full) - done=true - end - else - for kk=1,#blist do - local vv=blist[kk] - if find(lower(vv),path) then - local full=methodhandler('concatinators',variant,tag,vv,bname) or "" - result[#result+1]=resolve(full) - done=true - if not allresults then break end - end - end - end - end - return done -end local makewildcard=Cs( (P("^")^0*P("/")*P(-1)+P(-1))/".*"+(P("^")^0*P("/")/"")^0*(P("*")/".*"+P("-")/"%%-"+P(".")/"%%."+P("?")/"."+P("\\")/"/"+P(1))^0 ) function resolvers.wildcardpattern(pattern) return lpegmatch(makewildcard,pattern) or pattern end -local function findwildcardfiles(filename,allresults,result) - result=result or {} +local function findwildcardfiles(filename,allresults,result) + local result=result or {} local base=filebasename(filename) local dirn=filedirname(filename) local path=lower(lpegmatch(makewildcard,dirn) or dirn) local name=lower(lpegmatch(makewildcard,base) or base) - local files,done=instance.files,false + local files=instance.files if find(name,"*",1,true) then local hashes=instance.hashes + local function okay(found,path,base,hashname,hashtype) + if find(found,path) then + local full=methodhandler('concatinators',hashtype,hashname,found,base) + if full and full~="" then + result[#result+1]=resolveprefix(full) + return not allresults + end + end + end for k=1,#hashes do local hash=hashes[k] - local hashname,hashtype=hash.name,hash.type - for kk,hh in next,files[hashname] do - if not find(kk,"^remap:") then - if find(lower(kk),name) then - if doit(path,hh,kk,hashname,hashtype,result,allresults) then done=true end - if done and not allresults then break end + local hashname=hash.name + local hashtype=hash.type + if hashname and hashtype then + for found,base in filtered(files[hashname],name) do + if type(found)=='string' then + if okay(found,path,base,hashname,hashtype) then + break + end + else + for i=1,#found do + if okay(found[i],path,base,hashname,hashtype) then + break + end + end end end end end else + local function okayokay(found,path,base,hashname,hashtype) + if find(found,path) then + local full=methodhandler('concatinators',hashtype,hashname,found,base) + if full and full~="" then + result[#result+1]=resolveprefix(full) + return not allresults + end + end + end local hashes=instance.hashes for k=1,#hashes do local hash=hashes[k] - local hashname,hashtype=hash.name,hash.type - if doit(path,files[hashname][base],base,hashname,hashtype,result,allresults) then done=true end - if done and not allresults then break end + local hashname=hash.name + local hashtype=hash.type + if hashname and hashtype then + local found,base=lookup(content,base) + if not found then + elseif type(found)=='string' then + if okay(found,path,base,hashname,hashtype) then + break + end + else + for i=1,#found do + if okay(found[i],path,base,hashname,hashtype) then + break + end + end + end + end end end return result @@ -15095,7 +15291,7 @@ end function resolvers.dowithpath(name,func) local pathlist=resolvers.expandedpathlist(name) for i=1,#pathlist do - func("^"..resolvers.cleanpath(pathlist[i])) + func("^"..cleanpath(pathlist[i])) end end function resolvers.dowithvariable(name,func) @@ -15103,23 +15299,23 @@ function resolvers.dowithvariable(name,func) end function resolvers.locateformat(name) local engine=environment.ownmain or "luatex" - local barename=file.removesuffix(name) - local fullname=file.addsuffix(barename,"fmt") + local barename=removesuffix(name) + local fullname=addsuffix(barename,"fmt") local fmtname=caches.getfirstreadablefile(fullname,"formats",engine) or "" if fmtname=="" then fmtname=resolvers.findfile(fullname) - fmtname=resolvers.cleanpath(fmtname) + fmtname=cleanpath(fmtname) end if fmtname~="" then - local barename=file.removesuffix(fmtname) - local luaname=file.addsuffix(barename,luasuffixes.lua) - local lucname=file.addsuffix(barename,luasuffixes.luc) - local luiname=file.addsuffix(barename,luasuffixes.lui) - if lfs.isfile(luiname) then + local barename=removesuffix(fmtname) + local luaname=addsuffix(barename,luasuffixes.lua) + local lucname=addsuffix(barename,luasuffixes.luc) + local luiname=addsuffix(barename,luasuffixes.lui) + if isfile(luiname) then return barename,luiname - elseif lfs.isfile(lucname) then + elseif isfile(lucname) then return barename,lucname - elseif lfs.isfile(luaname) then + elseif isfile(luaname) then return barename,luaname end end @@ -15141,29 +15337,24 @@ function resolvers.dowithfilesintree(pattern,handle,before,after) local hash=hashes[i] local blobtype=hash.type local blobpath=hash.name - if blobpath then + if blobtype and blobpath then + local total=0 + local checked=0 + local done=0 if before then before(blobtype,blobpath,pattern) end - local files=instance.files[blobpath] - local total,checked,done=0,0,0 - if files then - for k,v in table.sortedhash(files) do - total=total+1 - if find(k,"^remap:") then - elseif find(k,pattern) then - if type(v)=="string" then - checked=checked+1 - if handle(blobtype,blobpath,v,k) then - done=done+1 - end - else - checked=checked+#v - for i=1,#v do - if handle(blobtype,blobpath,v[i],k) then - done=done+1 - end - end + for path,name in filtered(instance.files[blobpath],pattern) do + if type(path)=="string" then + checked=checked+1 + if handle(blobtype,blobpath,path,name) then + done=done+1 + end + else + checked=checked+#path + for i=1,#path do + if handle(blobtype,blobpath,path[i],name) then + done=done+1 end end end @@ -15174,8 +15365,8 @@ function resolvers.dowithfilesintree(pattern,handle,before,after) end end end -resolvers.obsolete=resolvers.obsolete or {} -local obsolete=resolvers.obsolete +local obsolete=resolvers.obsolete or {} +resolvers.obsolete=obsolete resolvers.find_file=resolvers.findfile obsolete.find_file=resolvers.findfile resolvers.find_files=resolvers.findfiles obsolete.find_files=resolvers.findfiles @@ -15186,7 +15377,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-pre"] = package.loaded["data-pre"] or true --- original size: 6643, stripped down to: 4401 +-- original size: 3106, stripped down to: 2563 if not modules then modules={} end modules ['data-pre']={ version=1.001, @@ -15196,44 +15387,51 @@ if not modules then modules={} end modules ['data-pre']={ license="see context related readme files" } local resolvers=resolvers -local prefixes=utilities.storage.allocate() -resolvers.prefixes=prefixes -local cleanpath,findgivenfile,expansion=resolvers.cleanpath,resolvers.findgivenfile,resolvers.expansion +local prefixes=resolvers.prefixes +local cleanpath=resolvers.cleanpath +local findgivenfile=resolvers.findgivenfile +local expansion=resolvers.expansion local getenv=resolvers.getenv -local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match -local joinpath,basename,dirname=file.join,file.basename,file.dirname -local getmetatable,rawset,type=getmetatable,rawset,type +local basename=file.basename +local dirname=file.dirname +local joinpath=file.join +local isfile=lfs.isfile prefixes.environment=function(str) return cleanpath(expansion(str)) end -prefixes.relative=function(str,n) - if io.exists(str) then - elseif io.exists("./"..str) then - str="./"..str - else - local p="../" - for i=1,n or 2 do - if io.exists(p..str) then - str=p..str - break - else - p=p.."../" +local function relative(str,n) + if not isfile(str) then + local pstr="./"..str + if isfile(pstr) then + str=pstr + else + local p="../" + for i=1,n or 2 do + local pstr=p..str + if isfile(pstr) then + str=pstr + break + else + p=p.."../" + end end end end return cleanpath(str) end +local function locate(str) + local fullname=findgivenfile(str) or "" + return cleanpath(fullname~="" and fullname or str) +end +prefixes.relative=relative +prefixes.locate=locate prefixes.auto=function(str) - local fullname=prefixes.relative(str) - if not lfs.isfile(fullname) then - fullname=prefixes.locate(str) + local fullname=relative(str) + if not isfile(fullname) then + fullname=locate(str) end return fullname end -prefixes.locate=function(str) - local fullname=findgivenfile(str) or "" - return cleanpath((fullname~="" and fullname) or str) -end prefixes.filename=function(str) local fullname=findgivenfile(str) or "" return cleanpath(basename((fullname~="" and fullname) or str)) @@ -15277,87 +15475,6 @@ prefixes.kpse=prefixes.locate prefixes.full=prefixes.locate prefixes.file=prefixes.filename prefixes.path=prefixes.pathname -function resolvers.allprefixes(separator) - local all=table.sortedkeys(prefixes) - if separator then - for i=1,#all do - all[i]=all[i]..":" - end - end - return all -end -local function _resolve_(method,target) - local action=prefixes[method] - if action then - return action(target) - else - return method..":"..target - end -end -local resolved,abstract={},{} -function resolvers.resetresolve(str) - resolved,abstract={},{} -end -local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) -local prefix=C(R("az")^2)*P(":") -local target=C((1-S(" \"\';,"))^1) -local notarget=(#S(";,")+P(-1))*Cc("") -local pattern=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) -local function resolve(str) - if type(str)=="table" then - local t={} - for i=1,#str do - t[i]=resolve(str[i]) - end - return t - else - local res=resolved[str] - if not res then - res=lpegmatch(pattern,str) - resolved[str]=res - abstract[res]=str - end - return res - end -end -local function unresolve(str) - return abstract[str] or str -end -resolvers.resolve=resolve -resolvers.unresolve=unresolve -if type(os.uname)=="function" then - for k,v in next,os.uname() do - if not prefixes[k] then - prefixes[k]=function() return v end - end - end -end -if os.type=="unix" then - local pattern - local function makepattern(t,k,v) - if t then - rawset(t,k,v) - end - local colon=P(":") - for k,v in table.sortedpairs(prefixes) do - if p then - p=P(k)+p - else - p=P(k) - end - end - pattern=Cs((p*colon+colon/";"+P(1))^0) - end - makepattern() - getmetatable(prefixes).__newindex=makepattern - function resolvers.repath(str) - return lpegmatch(pattern,str) - end -else - function resolvers.repath(str) - return str - end -end end -- of closure @@ -15419,7 +15536,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-fil"] = package.loaded["data-fil"] or true --- original size: 3801, stripped down to: 3231 +-- original size: 3863, stripped down to: 3310 if not modules then modules={} end modules ['data-fil']={ version=1.001, @@ -15431,30 +15548,31 @@ if not modules then modules={} end modules ['data-fil']={ local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_files=logs.reporter("resolvers","files") local resolvers=resolvers +local resolveprefix=resolvers.resolve local finders,openers,loaders,savers=resolvers.finders,resolvers.openers,resolvers.loaders,resolvers.savers local locators,hashers,generators,concatinators=resolvers.locators,resolvers.hashers,resolvers.generators,resolvers.concatinators local checkgarbage=utilities.garbagecollector and utilities.garbagecollector.check function locators.file(specification) - local name=specification.filename - local realname=resolvers.resolve(name) + local filename=specification.filename + local realname=resolveprefix(filename) if realname and realname~='' and lfs.isdir(realname) then if trace_locating then - report_files("file locator %a found as %a",name,realname) + report_files("file locator %a found as %a",filename,realname) end - resolvers.appendhash('file',name,true) + resolvers.appendhash('file',filename,true) elseif trace_locating then - report_files("file locator %a not found",name) + report_files("file locator %a not found",filename) end end function hashers.file(specification) - local name=specification.filename - local content=caches.loadcontent(name,'files') - resolvers.registerfilehash(name,content,content==nil) + local pathname=specification.filename + local content=caches.loadcontent(pathname,'files') + resolvers.registerfilehash(pathname,content,content==nil) end function generators.file(specification) - local path=specification.filename - local content=resolvers.scanfiles(path,false,true) - resolvers.registerfilehash(path,content,true) + local pathname=specification.filename + local content=resolvers.scanfiles(pathname,false,true) + resolvers.registerfilehash(pathname,content,true) end concatinators.file=file.join function finders.file(specification,filetype) @@ -15736,7 +15854,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-zip"] = package.loaded["data-zip"] or true --- original size: 8489, stripped down to: 6757 +-- original size: 9043, stripped down to: 7073 if not modules then modules={} end modules ['data-zip']={ version=1.001, @@ -15779,7 +15897,7 @@ function zip.openarchive(name) local arch=archives[name] if not arch then local full=resolvers.findfile(name) or "" - arch=(full~="" and zip.open(full)) or false + arch=full~="" and zip.open(full) or false archives[name]=arch end return arch @@ -15938,31 +16056,42 @@ function resolvers.usezipfile(archive) end end function resolvers.registerzipfile(z,tree) - local files,filter={},"" - if tree=="" then - filter="^(.+)/(.-)$" - else - filter=format("^%s/(.+)/(.-)$",tree) - end + local names={} + local files={} + local remap={} + local n=0 + local filter=tree=="" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree) + local register=resolvers.registerfile if trace_locating then report_zip("registering: using filter %a",filter) end - local register,n=resolvers.registerfile,0 for i in z:files() do - local path,name=match(i.filename,filter) - if path then - if name and name~='' then - register(files,name,path) - n=n+1 - else + local filename=i.filename + local path,name=match(filename,filter) + if not path then + n=n+1 + register(names,filename,"") + local usedname=lower(filename) + files[usedname]="" + if usedname~=filename then + remap[usedname]=filename end - else - register(files,i.filename,'') + elseif name and name~="" then n=n+1 + register(names,name,path) + local usedname=lower(name) + files[usedname]=path + if usedname~=name then + remap[usedname]=name + end + else end end report_zip("registering: %s files registered",n) - return files + return { + files=files, + remap=remap, + } end @@ -15972,7 +16101,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tre"] = package.loaded["data-tre"] or true --- original size: 2508, stripped down to: 2074 +-- original size: 4859, stripped down to: 3335 if not modules then modules={} end modules ['data-tre']={ version=1.001, @@ -15981,42 +16110,50 @@ if not modules then modules={} end modules ['data-tre']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local find,gsub,format=string.find,string.gsub,string.format +local find,gsub,lower=string.find,string.gsub,string.lower +local basename,dirname,joinname=file.basename,file.dirname,file .join +local globdir,isdir=dir.glob,lfs.isdir local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_trees=logs.reporter("resolvers","trees") local resolvers=resolvers -local done,found,notfound={},{},resolvers.finders.notfound -function resolvers.finders.tree(specification) +local resolveprefix=resolvers.resolve +local notfound=resolvers.finders.notfound +local collectors={} +local found={} +function resolvers.finders.tree(specification) local spec=specification.filename - local fnd=found[spec] - if fnd==nil then + local okay=found[spec] + if okay==nil then if spec~="" then - local path,name=file.dirname(spec),file.basename(spec) - if path=="" then path="." end - local hash=done[path] - if not hash then - local pattern=path.."/*" - hash=dir.glob(pattern) - done[path]=hash + local path=dirname(spec) + local name=basename(spec) + if path=="" then + path="." + end + local names=collectors[path] + if not names then + local pattern=find(path,"/%*+$") and path or (path.."/*") + names=globdir(pattern) + collectors[path]=names end local pattern="/"..gsub(name,"([%.%-%+])","%%%1").."$" - for k=1,#hash do - local v=hash[k] - if find(v,pattern) then - found[spec]=v - return v + for i=1,#names do + local fullname=names[i] + if find(fullname,pattern) then + found[spec]=fullname + return fullname end end end - fnd=notfound() - found[spec]=fnd + okay=notfound() + found[spec]=okay end - return fnd + return okay end function resolvers.locators.tree(specification) local name=specification.filename - local realname=resolvers.resolve(name) - if realname and realname~='' and lfs.isdir(realname) then + local realname=resolveprefix(name) + if realname and realname~='' and isdir(realname) then if trace_locating then report_trees("locator %a found",realname) end @@ -16033,10 +16170,43 @@ function resolvers.hashers.tree(specification) resolvers.methodhandler("hashers",name) resolvers.generators.file(specification) end -resolvers.concatinators.tree=resolvers.concatinators.file -resolvers.generators.tree=resolvers.generators.file -resolvers.openers.tree=resolvers.openers.file -resolvers.loaders.tree=resolvers.loaders.file +local collectors={} +table.setmetatableindex(collectors,function(t,k) + local rootname=gsub(k,"[/%*]+$","") + local dataname=joinname(rootname,"dirlist") + local data=caches.loadcontent(dataname,"files",dataname) + local content=data and data.content + local lookup=resolvers.get_from_content + if not content then + content=resolvers.scanfiles(rootname) + caches.savecontent(dataname,"files",content,dataname) + end + local files=content.files + local v=function(filename) + local path,name=lookup(content,filename) + if not path then + return filename + elseif type(path)=="table" then + path=path[1] + end + return joinname(rootname,path,name) + end + t[k]=v + return v +end) +function resolvers.finders.dirlist(specification) + local spec=specification.filename + if spec~="" then + local path,name=dirname(spec),basename(spec) + return path and collectors[path](name) or notfound() + end + return notfound() +end +resolvers.locators .dirlist=resolvers.locators .tree +resolvers.hashers .dirlist=resolvers.hashers .tree +resolvers.generators.dirlist=resolvers.generators.file +resolvers.openers .dirlist=resolvers.openers .file +resolvers.loaders .dirlist=resolvers.loaders .file end -- of closure @@ -16221,7 +16391,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-lua"] = package.loaded["data-lua"] or true --- original size: 4237, stripped down to: 3177 +-- original size: 4313, stripped down to: 3227 if not modules then modules={} end modules ['data-lua']={ version=1.001, @@ -16230,7 +16400,7 @@ if not modules then modules={} end modules ['data-lua']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local resolvers,package=resolvers,package +local package,lpeg=package,lpeg local gsub=string.gsub local concat=table.concat local addsuffix=file.addsuffix @@ -16241,9 +16411,11 @@ local luaformats={ 'TEXINPUTS','LUAINPUTS' } local libformats={ 'CLUAINPUTS' } local helpers=package.helpers or {} local methods=helpers.methods or {} +local resolvers=resolvers +local resolveprefix=resolvers.resolve +helpers.report=logs.reporter("resolvers","libraries") trackers.register("resolvers.libraries",function(v) helpers.trace=v end) trackers.register("resolvers.locating",function(v) helpers.trace=v end) -helpers.report=logs.reporter("resolvers","libraries") helpers.sequence={ "already loaded", "preload table", @@ -16258,7 +16430,7 @@ helpers.sequence={ } local pattern=Cs(P("!")^0/""*(P("/")*P(-1)/"/"+P("/")^1/"/"+1)^0) function helpers.cleanpath(path) - return resolvers.resolve(lpegmatch(pattern,path)) + return resolveprefix(lpegmatch(pattern,path)) end local loadedaslib=helpers.loadedaslib local getextraluapaths=package.extraluapaths @@ -16395,7 +16567,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tmf"] = package.loaded["data-tmf"] or true --- original size: 2600, stripped down to: 1627 +-- original size: 2601, stripped down to: 1627 if not modules then modules={} end modules ['data-tmf']={ version=1.001, @@ -16451,7 +16623,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-lst"] = package.loaded["data-lst"] or true --- original size: 2654, stripped down to: 2301 +-- original size: 2734, stripped down to: 2354 if not modules then modules={} end modules ['data-lst']={ version=1.001, @@ -16460,10 +16632,13 @@ if not modules then modules={} end modules ['data-lst']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local find,concat,upper,format=string.find,table.concat,string.upper,string.format +local rawget,type,next=rawget,type,next +local find,concat,upper=string.find,table.concat,string.upper local fastcopy,sortedpairs=table.fastcopy,table.sortedpairs -resolvers.listers=resolvers.listers or {} local resolvers=resolvers +local listers=resolvers.listers or {} +resolvers.listers=listers +local resolveprefix=resolvers.resolve local report_lists=logs.reporter("resolvers","lists") local function tabstr(str) if type(str)=='table' then @@ -16472,7 +16647,7 @@ local function tabstr(str) return str end end -function resolvers.listers.variables(pattern) +function listers.variables(pattern) local instance=resolvers.instance local environment=instance.environment local variables=instance.variables @@ -16493,10 +16668,10 @@ function resolvers.listers.variables(pattern) for key,value in sortedpairs(configured) do if key~="" and (pattern=="" or find(upper(key),pattern)) then report_lists(key) - report_lists(" env: %s",tabstr(rawget(environment,key)) or "unset") - report_lists(" var: %s",tabstr(configured[key]) or "unset") - report_lists(" exp: %s",tabstr(expansions[key]) or "unset") - report_lists(" res: %s",tabstr(resolvers.resolve(expansions[key])) or "unset") + report_lists(" env: %s",tabstr(rawget(environment,key)) or "unset") + report_lists(" var: %s",tabstr(configured[key]) or "unset") + report_lists(" exp: %s",tabstr(expansions[key]) or "unset") + report_lists(" res: %s",tabstr(resolveprefix(expansions[key])) or "unset") end end instance.environment=fastcopy(env) @@ -16504,15 +16679,15 @@ function resolvers.listers.variables(pattern) instance.expansions=fastcopy(exp) end local report_resolved=logs.reporter("system","resolved") -function resolvers.listers.configurations() +function listers.configurations() local configurations=resolvers.instance.specification for i=1,#configurations do - report_resolved("file : %s",resolvers.resolve(configurations[i])) + report_resolved("file : %s",resolveprefix(configurations[i])) end report_resolved("") local list=resolvers.expandedpathfromlist(resolvers.splitpath(resolvers.luacnfspec)) for i=1,#list do - local li=resolvers.resolve(list[i]) + local li=resolveprefix(list[i]) if lfs.isdir(li) then report_resolved("path - %s",li) else @@ -16951,8 +17126,8 @@ end -- of closure -- used libraries : l-lua.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-sto.lua util-prs.lua util-fmt.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-mrg.lua util-tpl.lua util-env.lua luat-env.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua util-lib.lua luat-sta.lua luat-fmt.lua -- skipped libraries : - --- original bytes : 699655 --- stripped bytes : 249540 +-- original bytes : 704727 +-- stripped bytes : 250243 -- end library merge diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun index 189fc4b7b..70f493525 100755 --- a/scripts/context/stubs/unix/mtxrun +++ b/scripts/context/stubs/unix/mtxrun @@ -1195,7 +1195,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-table"] = package.loaded["l-table"] or true --- original size: 31828, stripped down to: 20814 +-- original size: 33243, stripped down to: 21578 if not modules then modules={} end modules ['l-table']={ version=1.001, @@ -1342,14 +1342,14 @@ local function sortedhash(t,cmp) end local n=0 local m=#s - local function kv(s) + local function kv() if n<m then n=n+1 local k=s[n] return k,t[k] end end - return kv,s + return kv else return nothing end @@ -2110,6 +2110,44 @@ function table.values(t,s) return {} end end +function table.filtered(t,pattern,sort,cmp) + if t and type(pattern)=="string" then + if sort then + local s + if cmp then + s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) + else + s=sortedkeys(t) + end + local n=0 + local m=#s + local function kv(s) + while n<m do + n=n+1 + local k=s[n] + if find(k,pattern) then + return k,t[k] + end + end + end + return kv,s + else + local n=next(t) + local function iterator() + while n do + local k=n + n=next(t,k) + if find(k,pattern) then + return k,t[k] + end + end + end + return iterator,t + end + else + return nothing + end +end end -- of closure @@ -3775,7 +3813,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-dir"] = package.loaded["l-dir"] or true --- original size: 14788, stripped down to: 9096 +-- original size: 16056, stripped down to: 10707 if not modules then modules={} end modules ['l-dir']={ version=1.001, @@ -3785,7 +3823,7 @@ if not modules then modules={} end modules ['l-dir']={ license="see context related readme files" } local type,select=type,select -local find,gmatch,match,gsub=string.find,string.gmatch,string.match,string.gsub +local find,gmatch,match,gsub,sub=string.find,string.gmatch,string.match,string.gsub,string.sub local concat,insert,remove,unpack=table.concat,table.insert,table.remove,table.unpack local lpegmatch=lpeg.match 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 @@ -3794,54 +3832,123 @@ local dir=dir local lfs=lfs local attributes=lfs.attributes local walkdir=lfs.dir -local isdir=lfs.isdir -local isfile=lfs.isfile +local isdir=lfs.isdir +local isfile=lfs.isfile local currentdir=lfs.currentdir local chdir=lfs.chdir local mkdir=lfs.mkdir local onwindows=os.type=="windows" or find(os.getenv("PATH"),";",1,true) -if not isdir then - function isdir(name) - local a=attributes(name) - return a and a.mode=="directory" +if onwindows then + isdir=function(name) + name=gsub(name,"([/\\]+)$","/.") + return attributes(name,"mode")=="directory" + end + isfile=function(name) + return attributes(name,"mode")=="file" end lfs.isdir=isdir -end -if not isfile then - function isfile(name) - local a=attributes(name) - return a and a.mode=="file" + lfs.isfile=isfile +else + isdir=function(name) + return attributes(name,"mode")=="directory" + end + isfile=function(name) + return attributes(name,"mode")=="file" end + lfs.isdir=isdir lfs.isfile=isfile end function dir.current() return (gsub(currentdir(),"\\","/")) end -local lfsisdir=isdir -local function isdir(path) - path=gsub(path,"[/\\]+$","") - return lfsisdir(path) +local function glob_pattern_function(path,patt,recurse,action) + if isdir(path) then + local usedpath + if path=="/" then + usedpath="/." + elseif not find(path,"/$") then + usedpath=path.."/." + path=path.."/" + else + usedpath=path + end + local dirs + for name in walkdir(usedpath) do + if name~="." and name~=".." then + local full=path..name + local mode=attributes(full,'mode') + if mode=='file' then + if not patt or find(full,patt) then + action(full) + end + elseif recurse and mode=="directory" then + if not dirs then + dirs={ full } + else + dirs[#dirs+1]=full + end + end + end + end + if dirs then + for i=1,#dirs do + glob_pattern_function(dirs[i],patt,recurse,action) + end + end + end end -lfs.isdir=isdir -local function globpattern(path,patt,recurse,action) - if path=="/" then - path=path.."." - elseif not find(path,"/$") then - path=path..'/' - end - if isdir(path) then - for name in walkdir(path) do - local full=path..name - local mode=attributes(full,'mode') - if mode=='file' then - if find(full,patt) then - action(full) +local function glob_pattern_table(path,patt,recurse,result) + if not result then + result={} + end + if isdir(path) then + local usedpath + if path=="/" then + usedpath="/." + elseif not find(path,"/$") then + usedpath=path.."/." + path=path.."/" + else + usedpath=path + end + local dirs + for name in walkdir(usedpath) do + if name~="." and name~=".." then + local full=path..name + local mode=attributes(full,'mode') + if mode=='file' then + if not patt or find(full,patt) then + result[#result+1]=full + end + elseif recurse and mode=="directory" then + if not dirs then + dirs={ full } + else + dirs[#dirs+1]=full + end end - elseif recurse and (mode=="directory") and (name~='.') and (name~="..") then - globpattern(full,patt,recurse,action) + end + end + if dirs then + for i=1,#dirs do + glob_pattern_table(dirs[i],patt,recurse,result) end end end + return result +end +local function globpattern(path,patt,recurse,method) + local kind=type(method) + if pattern and sub(patt,1,-3)==path then + patt=false + end + if kind=="function" then + return glob_pattern_function(path,patt,recurse,method) + elseif kind=="table" then + return glob_pattern_table(path,patt,recurse,method) + else + return glob_pattern_table(path,patt,recurse,{}) + end end dir.globpattern=globpattern local function collectpattern(path,patt,recurse,result) @@ -3853,18 +3960,24 @@ local function collectpattern(path,patt,recurse,result) ok,scanner,first=xpcall(function() return walkdir(path) end,function() end) end if ok and type(scanner)=="function" then - if not find(path,"/$") then path=path..'/' end + if not find(path,"/$") then + path=path..'/' + end for name in scanner,first do - local full=path..name - local attr=attributes(full) - local mode=attr.mode - if mode=='file' then - if find(full,patt) then + if name=="." then + elseif name==".." then + else + 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" then + attr.list=collectpattern(full,patt,recurse) result[name]=attr end - elseif recurse and (mode=="directory") and (name~='.') and (name~="..") then - attr.list=collectpattern(full,patt,recurse) - result[name]=attr end end end @@ -3872,15 +3985,15 @@ local function collectpattern(path,patt,recurse,result) end dir.collectpattern=collectpattern local separator -if onwindows then +if onwindows then local slash=S("/\\")/"/" - pattern=Ct { + pattern={ [1]=(Cs(P(".")+slash^1)+Cs(R("az","AZ")*P(":")*slash^0)+Cc("./"))*V(2)*V(3), [2]=Cs(((1-S("*?/\\"))^0*slash)^0), [3]=Cs(P(1)^0) } -else - pattern=Ct { +else + pattern={ [1]=(C(P(".")+P("/")^1)+Cc("./"))*V(2)*V(3), [2]=C(((1-S("*?/"))^0*P("/"))^0), [3]=C(P(1)^0) @@ -3898,9 +4011,8 @@ local function glob(str,t) elseif 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 root,path,base=lpegmatch(pattern,str) + if root and path and base then local recurse=find(base,"**",1,true) local start=root..path local result=lpegmatch(filter,start..base) @@ -3922,16 +4034,12 @@ local function glob(str,t) return { str } end 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 root,path,base=lpegmatch(pattern,str) + if root and path and base then local recurse=find(base,"**",1,true) local start=root..path local result=lpegmatch(filter,start..base) - globpattern(start,result,recurse,action) - return t + return globpattern(start,result,recurse,t) else return {} end @@ -4879,7 +4987,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-str"] = package.loaded["util-str"] or true --- original size: 33485, stripped down to: 18420 +-- original size: 34240, stripped down to: 18733 if not modules then modules={} end modules ['util-str']={ version=1.001, @@ -5544,6 +5652,15 @@ else add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=lpeg.patterns.texescape }) add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=lpeg.patterns.luaescape }) end +local dquote=patterns.dquote +local equote=patterns.escaped+dquote/'\\"'+1 +local space=patterns.space +local cquote=Cc('"') +local pattern=Cs(dquote*(equote-P(-2))^0*dquote) ++Cs(cquote*(equote-space)^0*space*equote^0*cquote) +function string.optionalquoted(str) + return lpegmatch(pattern,str) or str +end end -- of closure @@ -8717,7 +8834,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-env"] = package.loaded["util-env"] or true --- original size: 8814, stripped down to: 5092 +-- original size: 8022, stripped down to: 5038 if not modules then modules={} end modules ['util-env']={ version=1.001, @@ -8728,7 +8845,7 @@ if not modules then modules={} end modules ['util-env']={ } local allocate,mark=utilities.storage.allocate,utilities.storage.mark local format,sub,match,gsub,find=string.format,string.sub,string.match,string.gsub,string.find -local unquoted,quoted=string.unquoted,string.quoted +local unquoted,quoted,optionalquoted=string.unquoted,string.quoted,string.optionalquoted local concat,insert,remove=table.concat,table.insert,table.remove environment=environment or {} local environment=environment @@ -8841,24 +8958,14 @@ function environment.splitarguments(separator) return before,after end function environment.reconstructcommandline(arg,noquote) + local resolveprefix=resolvers.resolve arg=arg or environment.originalarguments if noquote and #arg==1 then - local a=arg[1] - a=resolvers.resolve(a) - a=unquoted(a) - return a + return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1]) elseif #arg>0 then local result={} for i=1,#arg do - local a=arg[i] - a=resolvers.resolve(a) - a=unquoted(a) - a=gsub(a,'"','\\"') - if find(a," ",1,true) then - result[#result+1]=quoted(a) - else - result[#result+1]=a - end + result[i]=optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix) end return concat(result," ") else @@ -12483,7 +12590,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-ini"] = package.loaded["data-ini"] or true --- original size: 7927, stripped down to: 5528 +-- original size: 10598, stripped down to: 7341 if not modules then modules={} end modules ['data-ini']={ version=1.001, @@ -12492,14 +12599,15 @@ if not modules then modules={} end modules ['data-ini']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files", } +local next,type,getmetatable,rawset=next,type,getmetatable,rawset local gsub,find,gmatch,char=string.gsub,string.find,string.gmatch,string.char -local next,type=next,type local filedirname,filebasename,filejoin=file.dirname,file.basename,file.join +local ostype,osname,osuname,ossetenv,osgetenv=os.type,os.name,os.uname,os.setenv,os.getenv +local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local trace_detail=false trackers.register("resolvers.details",function(v) trace_detail=v end) local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) local report_initialization=logs.reporter("resolvers","initialization") -local ostype,osname,ossetenv,osgetenv=os.type,os.name,os.setenv,os.getenv resolvers=resolvers or {} local resolvers=resolvers texconfig.kpse_init=false @@ -12632,10 +12740,88 @@ if type(profiler)=="table" and not jit then profiler.start("luatex-profile.log") end) end -if not resolvers.resolve then - function resolvers.resolve (s) return s end - function resolvers.unresolve(s) return s end - function resolvers.repath (s) return s end +local prefixes=utilities.storage.allocate() +resolvers.prefixes=prefixes +local resolved={} +local abstract={} +function resolvers.resetresolve(str) + resolved,abstract={},{} +end +function resolvers.allprefixes(separator) + local all=table.sortedkeys(prefixes) + if separator then + for i=1,#all do + all[i]=all[i]..":" + end + end + return all +end +local function _resolve_(method,target) + local action=prefixes[method] + if action then + return action(target) + else + return method..":"..target + end +end +function resolvers.unresolve(str) + return abstract[str] or str +end +local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) +local prefix=C(R("az")^2)*P(":") +local target=C((1-S(" \"\';,"))^1) +local notarget=(#S(";,")+P(-1))*Cc("") +local pattern=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) +local function resolve(str) + if type(str)=="table" then + local res={} + for i=1,#str do + res[i]=resolve(str[i]) + end + return res + else + local res=resolved[str] + if not res then + res=lpegmatch(pattern,str) + resolved[str]=res + abstract[res]=str + end + return res + end +end +resolvers.resolve=resolve +if type(osuname)=="function" then + for k,v in next,osuname() do + if not prefixes[k] then + prefixes[k]=function() return v end + end + end +end +if ostype=="unix" then + local pattern + local function makepattern(t,k,v) + if t then + rawset(t,k,v) + end + local colon=P(":") + for k,v in table.sortedpairs(prefixes) do + if p then + p=P(k)+p + else + p=P(k) + end + end + pattern=Cs((p*colon+colon/";"+P(1))^0) + end + makepattern() + table.setmetatablenewindex(prefixes,makepattern) + function resolvers.repath(str) + return lpegmatch(pattern,str) + end +else + function resolvers.repath(str) + return str + end end @@ -12645,7 +12831,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-exp"] = package.loaded["data-exp"] or true --- original size: 15317, stripped down to: 9723 +-- original size: 16463, stripped down to: 10113 if not modules then modules={} end modules ['data-exp']={ version=1.001, @@ -12660,11 +12846,14 @@ local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns local Ct,Cs,Cc,Carg,P,C,S=lpeg.Ct,lpeg.Cs,lpeg.Cc,lpeg.Carg,lpeg.P,lpeg.C,lpeg.S local type,next=type,next local ostype=os.type -local collapsepath=file.collapsepath +local collapsepath,joinpath,basename=file.collapsepath,file.join,file.basename local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_globbing=true trackers.register("resolvers.globbing",function(v) trace_globbing=v end) local report_expansions=logs.reporter("resolvers","expansions") +local report_globbing=logs.reporter("resolvers","globbing") local resolvers=resolvers +local resolveprefix=resolvers.resolve local function f_both(a,b) local t,n={},0 for sb in gmatch(b,"[^,]+") do @@ -12754,35 +12943,27 @@ function resolvers.expandedpathfromlist(pathlist) end return newlist end -local cleanup=lpeg.replacer { - { "!","" }, - { "\\","/" }, -} -function resolvers.cleanpath(str) - local doslashes=(P("\\")/"/"+1)^0 - local donegation=(P("!")/"" )^0 - local homedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") - if homedir=="~" or homedir=="" or not lfs.isdir(homedir) then - if trace_expansions then - report_expansions("no home dir set, ignoring dependent paths") - end - function resolvers.cleanpath(str) - if not str or find(str,"~",1,true) then - return "" - else - return lpegmatch(cleanup,str) +local usedhomedir=nil +local donegation=(P("!")/"" )^0 +local doslashes=(P("\\")/"/"+1)^0 +local function expandedhome() + if not usedhomedir then + usedhomedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") + if usedhomedir=="~" or usedhomedir=="" or not lfs.isdir(usedhomedir) then + if trace_expansions then + report_expansions("no home dir set, ignoring dependent path using current path") end - end - else - local dohome=((P("~")+P("$HOME"))/homedir)^0 - local cleanup=Cs(donegation*dohome*doslashes) - function resolvers.cleanpath(str) - return str and lpegmatch(cleanup,str) or "" + usedhomedir="." end end - return resolvers.cleanpath(str) + return usedhomedir +end +local dohome=((P("~")+P("$HOME")+P("%HOME%"))/expandedhome)^0 +local cleanup=Cs(donegation*dohome*doslashes) +resolvers.cleanpath=function(str) + return str and lpegmatch(cleanup,str) or "" end -local expandhome=P("~")/"$HOME" +local expandhome=P("~")/"$HOME" local dodouble=P('"')/""*(expandhome+(1-P('"')))^0*P('"')/"" local dosingle=P("'")/""*(expandhome+(1-P("'")))^0*P("'")/"" local dostring=(expandhome+1 )^0 @@ -12834,7 +13015,7 @@ function resolvers.splitpath(str) end function resolvers.joinpath(str) if type(str)=='table' then - return file.joinpath(str) + return joinpath(str) else return str end @@ -12845,35 +13026,54 @@ local timer={} local scanned={} local nofscans=0 local scancache={} -local function scan(files,spec,path,n,m,r) - local full=(path=="" and spec) or (spec..path..'/') +local fullcache={} +local nofsharedscans=0 +local function scan(files,remap,spec,path,n,m,r,onlyone) + local full=path=="" and spec or (spec..path..'/') local dirs={} local nofdirs=0 for name in directory(full) do if not lpegmatch(weird,name) then - local mode=attributes(full..name,'mode') - if mode=='file' then + local mode=attributes(full..name,"mode") + if mode=="file" then n=n+1 - local f=files[name] - if f then - if type(f)=='string' then - files[name]={ f,path } + local lower=lower(name) + local paths=files[lower] + if paths then + if onlyone then else - f[#f+1]=path + if type(paths)=="string" then + files[lower]={ paths,path } + else + paths[#paths+1]=path + end + if name~=lower then + local rl=remap[lower] + if not rl then + remap[lower]=name + r=r+1 + elseif trace_globbing and rl~=name then + report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) + end + end end else - files[name]=path - local lower=lower(name) + files[lower]=path if name~=lower then - files["remap:"..lower]=name - r=r+1 + local rl=remap[lower] + if not rl then + remap[lower]=name + r=r+1 + elseif trace_globbing and rl~=name then + report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) + end end end - elseif mode=='directory' then + elseif mode=="directory" then m=m+1 nofdirs=nofdirs+1 if path~="" then - dirs[nofdirs]=path..'/'..name + dirs[nofdirs]=path.."/"..name else dirs[nofdirs]=name end @@ -12883,107 +13083,52 @@ local function scan(files,spec,path,n,m,r) if nofdirs>0 then sort(dirs) for i=1,nofdirs do - files,n,m,r=scan(files,spec,dirs[i],n,m,r) + files,remap,n,m,r=scan(files,remap,spec,dirs[i],n,m,r,onlyone) end end scancache[sub(full,1,-2)]=files - return files,n,m,r + return files,remap,n,m,r end -local fullcache={} -function resolvers.scanfiles(path,branch,usecache) - statistics.starttiming(timer) - local realpath=resolvers.resolve(path) +function resolvers.scanfiles(path,branch,usecache,onlyonce) + local realpath=resolveprefix(path) if usecache then - local files=fullcache[realpath] - if files then + local content=fullcache[realpath] + if content then if trace_locating then - report_expansions("using caches scan of path %a, branch %a",path,branch or path) + report_expansions("using cached scan of path %a, branch %a",path,branch or path) end - return files + nofsharedscans=nofsharedscans+1 + return content end end + statistics.starttiming(timer) if trace_locating then report_expansions("scanning path %a, branch %a",path,branch or path) end - local files,n,m,r=scan({},realpath..'/',"",0,0,0) - files.__path__=path - files.__files__=n - files.__directories__=m - files.__remappings__=r + local files,remap,n,m,r=scan({},{},realpath..'/',"",0,0,0,onlyonce) + local content={ + metadata={ + path=path, + files=n, + directories=m, + remappings=r, + }, + files=files, + remap=remap, + } if trace_locating then report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r) end if usecache then scanned[#scanned+1]=realpath - fullcache[realpath]=files + fullcache[realpath]=content end nofscans=nofscans+1 statistics.stoptiming(timer) - return files -end -local function simplescan(files,spec,path) - local full=(path=="" and spec) or (spec..path..'/') - local dirs={} - local nofdirs=0 - for name in directory(full) do - if not lpegmatch(weird,name) then - local mode=attributes(full..name,'mode') - if mode=='file' then - if not files[name] then - files[name]=path - end - elseif mode=='directory' then - nofdirs=nofdirs+1 - if path~="" then - dirs[nofdirs]=path..'/'..name - else - dirs[nofdirs]=name - end - end - end - end - if nofdirs>0 then - sort(dirs) - for i=1,nofdirs do - files=simplescan(files,spec,dirs[i]) - end - end - return files + return content end -local simplecache={} -local nofsharedscans=0 function resolvers.simplescanfiles(path,branch,usecache) - statistics.starttiming(timer) - local realpath=resolvers.resolve(path) - if usecache then - local files=simplecache[realpath] - if not files then - files=scancache[realpath] - if files then - nofsharedscans=nofsharedscans+1 - end - end - if files then - if trace_locating then - report_expansions("using caches scan of path %a, branch %a",path,branch or path) - end - return files - end - end - if trace_locating then - report_expansions("scanning path %a, branch %a",path,branch or path) - end - local files=simplescan({},realpath..'/',"") - if trace_locating then - report_expansions("%s files found",table.count(files)) - end - if usecache then - scanned[#scanned+1]=realpath - simplecache[realpath]=files - end - nofscans=nofscans+1 - statistics.stoptiming(timer) - return files + return resolvers.scanfiles(path,branch,usecache,true) end function resolvers.scandata() table.sort(scanned) @@ -12994,6 +13139,49 @@ function resolvers.scandata() paths=scanned, } end +function resolvers.get_from_content(content,path,name) + local files=content.files + if not files then + return + end + local remap=content.remap + if not remap then + return + end + if name then + local used=lower(name) + return path,remap[used] or used + else + local name=path + local used=lower(name) + local path=files[used] + if path then + return path,remap[used] or used + end + end +end +local nothing=function() end +function resolvers.filtered_from_content(content,pattern) + if content and type(pattern)=="string" then + local pattern=lower(pattern) + local files=content.files + local remap=content.remap + if files and remap then + local n=next(files) + local function iterator() + while n do + local k=n + n=next(files,k) + if find(k,pattern) then + return files[k],remap and remap[k] or k + end + end + end + return iterator + end + end + return nothing +end end -- of closure @@ -13272,7 +13460,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tmp"] = package.loaded["data-tmp"] or true --- original size: 15532, stripped down to: 11648 +-- original size: 15681, stripped down to: 11761 if not modules then modules={} end modules ['data-tmp']={ version=1.100, @@ -13291,6 +13479,7 @@ local trace_cache=false trackers.register("resolvers.cache",function(v) trace_ca local report_caches=logs.reporter("resolvers","caches") local report_resolvers=logs.reporter("resolvers","caching") local resolvers=resolvers +local cleanpath=resolvers.cleanpath local directive_cleanup=false directives.register("system.compile.cleanup",function(v) directive_cleanup=v end) local directive_strip=false directives.register("system.compile.strip",function(v) directive_strip=v end) local compile=utilities.lua.compile @@ -13312,7 +13501,7 @@ caches.relocate=false caches.defaults={ "TMPDIR","TEMPDIR","TMP","TEMP","HOME","HOMEPATH" } local writable,readables,usedreadables=nil,{},{} local function identify() - local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") + local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") if texmfcaches then for k=1,#texmfcaches do local cachepath=texmfcaches[k] @@ -13566,10 +13755,12 @@ local content_state={} function caches.contentstate() return content_state or {} end -function caches.loadcontent(cachename,dataname) - local name=caches.hashed(cachename) - local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") - local filename=file.join(path,name) +function caches.loadcontent(cachename,dataname,filename) + if not filename then + local name=caches.hashed(cachename) + local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") + filename=file.join(path,name) + end local blob=loadfile(addsuffix(filename,luasuffixes.luc)) or loadfile(addsuffix(filename,luasuffixes.lua)) if blob then local data=blob() @@ -13601,10 +13792,12 @@ function caches.collapsecontent(content) end end end -function caches.savecontent(cachename,dataname,content) - local name=caches.hashed(cachename) - local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") - local filename=file.join(path,name) +function caches.savecontent(cachename,dataname,content,filename) + if not filename then + local name=caches.hashed(cachename) + local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") + filename=file.join(path,name) + end local luaname=addsuffix(filename,luasuffixes.lua) local lucname=addsuffix(filename,luasuffixes.luc) if trace_locating then @@ -13647,7 +13840,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-met"] = package.loaded["data-met"] or true --- original size: 5460, stripped down to: 4014 +-- original size: 5347, stripped down to: 4015 if not modules then modules={} end modules ['data-met']={ version=1.100, @@ -13675,7 +13868,7 @@ local function splitmethod(filename) if type(filename)=="table" then return filename end - filename=file.collapsepath(filename,".") + filename=file.collapsepath(filename,".") if not find(filename,"://",1,true) then return { scheme="file",path=filename,original=filename,filename=filename } end @@ -13766,7 +13959,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-res"] = package.loaded["data-res"] or true --- original size: 62045, stripped down to: 43116 +-- original size: 61031, stripped down to: 42613 if not modules then modules={} end modules ['data-res']={ version=1.001, @@ -13776,7 +13969,7 @@ if not modules then modules={} end modules ['data-res']={ license="see context related readme files", } local gsub,find,lower,upper,match,gmatch=string.gsub,string.find,string.lower,string.upper,string.match,string.gmatch -local concat,insert,sortedkeys=table.concat,table.insert,table.sortedkeys +local concat,insert,sortedkeys,sortedhash=table.concat,table.insert,table.sortedkeys,table.sortedhash local next,type,rawget=next,type,rawget local os=os local P,S,R,C,Cc,Cs,Ct,Carg=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cc,lpeg.Cs,lpeg.Ct,lpeg.Carg @@ -13785,14 +13978,19 @@ local formatters=string.formatters local filedirname=file.dirname local filebasename=file.basename local suffixonly=file.suffixonly +local addsuffix=file.addsuffix +local removesuffix=file.removesuffix local filejoin=file.join local collapsepath=file.collapsepath local joinpath=file.joinpath +local is_qualified_path=file.is_qualified_path local allocate=utilities.storage.allocate local settings_to_array=utilities.parsers.settings_to_array +local getcurrentdir=lfs.currentdir +local isfile=lfs.isfile +local isdir=lfs.isdir local setmetatableindex=table.setmetatableindex local luasuffixes=utilities.lua.suffixes -local getcurrentdir=lfs.currentdir local trace_locating=false trackers .register("resolvers.locating",function(v) trace_locating=v end) local trace_detail=false trackers .register("resolvers.details",function(v) trace_detail=v end) local trace_expansions=false trackers .register("resolvers.expansions",function(v) trace_expansions=v end) @@ -13803,10 +14001,14 @@ local expandedpathfromlist=resolvers.expandedpathfromlist local checkedvariable=resolvers.checkedvariable local splitconfigurationpath=resolvers.splitconfigurationpath local methodhandler=resolvers.methodhandler +local filtered=resolvers.filtered_from_content +local lookup=resolvers.get_from_content +local cleanpath=resolvers.cleanpath +local resolveprefix=resolvers.resolve local initializesetter=utilities.setters.initialize local ostype,osname,osenv,ossetenv,osgetenv=os.type,os.name,os.env,os.setenv,os.getenv -resolvers.cacheversion='1.0.1' -resolvers.configbanner='' +resolvers.cacheversion="1.100" +resolvers.configbanner="" resolvers.homedir=environment.homedir resolvers.criticalvars=allocate { "SELFAUTOLOC","SELFAUTODIR","SELFAUTOPARENT","TEXMFCNF","TEXMF","TEXOS" } resolvers.luacnfname="texmfcnf.lua" @@ -13833,7 +14035,7 @@ local instance=resolvers.instance or nil function resolvers.setenv(key,value,raw) if instance then instance.environment[key]=value - ossetenv(key,raw and value or resolvers.resolve(value)) + ossetenv(key,raw and value or resolveprefix(value)) end end local function getenv(key) @@ -13847,7 +14049,7 @@ local function getenv(key) end resolvers.getenv=getenv resolvers.env=getenv -local function resolve(k) +local function resolvevariable(k) return instance.expansions[k] end local dollarstripper=lpeg.stripper("$") @@ -13856,19 +14058,19 @@ local backslashswapper=lpeg.replacer("\\","/") local somevariable=P("$")/"" local somekey=C(R("az","AZ","09","__","--")^1) local somethingelse=P(";")*((1-S("!{}/\\"))^1*P(";")/"")+P(";")*(P(";")/"")+P(1) -local variableexpander=Cs((somevariable*(somekey/resolve)+somethingelse)^1 ) +local variableexpander=Cs((somevariable*(somekey/resolvevariable)+somethingelse)^1 ) local cleaner=P("\\")/"/"+P(";")*S("!{}/\\")^0*P(";")^1/";" local variablecleaner=Cs((cleaner+P(1))^0) -local somevariable=R("az","AZ","09","__","--")^1/resolve +local somevariable=R("az","AZ","09","__","--")^1/resolvevariable local variable=(P("$")/"")*(somevariable+(P("{")/"")*somevariable*(P("}")/"")) local variableresolver=Cs((variable+P(1))^0) local function expandedvariable(var) return lpegmatch(variableexpander,var) or var end -function resolvers.newinstance() - if trace_locating then +function resolvers.newinstance() + if trace_locating then report_resolving("creating instance") - end + end local environment,variables,expansions,order=allocate(),allocate(),allocate(),allocate() local newinstance={ environment=environment, @@ -13995,13 +14197,13 @@ local function identify_configuration_files() for i=1,#cnfpaths do local filepath=cnfpaths[i] local filename=collapsepath(filejoin(filepath,luacnfname)) - local realname=resolvers.resolve(filename) + local realname=resolveprefix(filename) if trace_locating then - local fullpath=gsub(resolvers.resolve(collapsepath(filepath)),"//","/") + local fullpath=gsub(resolveprefix(collapsepath(filepath)),"//","/") local weirdpath=find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c",1,true) report_resolving("looking for %a on %s path %a from specification %a",luacnfname,weirdpath and "weird" or "given",fullpath,filepath) end - if lfs.isfile(realname) then + if isfile(realname) then specification[#specification+1]=filename if trace_locating then report_resolving("found configuration file %a",realname) @@ -14023,7 +14225,7 @@ local function load_configuration_files() local filename=specification[i] local pathname=filedirname(filename) local filename=filejoin(pathname,luacnfname) - local realname=resolvers.resolve(filename) + local realname=resolveprefix(filename) local blob=loadfile(realname) if blob then local setups=instance.setups @@ -14031,7 +14233,7 @@ local function load_configuration_files() local parent=data and data.parent if parent then local filename=filejoin(pathname,parent) - local realname=resolvers.resolve(filename) + local realname=resolveprefix(filename) local blob=loadfile(realname) if blob then local parentdata=blob() @@ -14056,7 +14258,7 @@ local function load_configuration_files() elseif variables[k]==nil then if trace_locating and not warning then report_resolving("variables like %a in configuration file %a should move to the 'variables' subtable", - k,resolvers.resolve(filename)) + k,resolveprefix(filename)) warning=true end variables[k]=v @@ -14116,7 +14318,7 @@ local function locate_file_databases() local stripped=lpegmatch(inhibitstripper,path) if stripped~="" then local runtime=stripped==path - path=resolvers.cleanpath(path) + path=cleanpath(path) local spec=resolvers.splitmethod(stripped) if runtime and (spec.noscheme or spec.scheme=="file") then stripped="tree:///"..stripped @@ -14179,8 +14381,8 @@ function resolvers.renew(hashname) report_resolving("identifying tree %a",hashname) end end - local realpath=resolvers.resolve(hashname) - if lfs.isdir(realpath) then + local realpath=resolveprefix(hashname) + if isdir(realpath) then if trace_locating then report_resolving("using path %a",realpath) end @@ -14308,7 +14510,7 @@ function resolvers.registerextrapath(paths,subpaths) local ps=p.."/"..s if not done[ps] then newn=newn+1 - ep[newn]=resolvers.cleanpath(ps) + ep[newn]=cleanpath(ps) done[ps]=true end end @@ -14318,7 +14520,7 @@ function resolvers.registerextrapath(paths,subpaths) local p=paths[i] if not done[p] then newn=newn+1 - ep[newn]=resolvers.cleanpath(p) + ep[newn]=cleanpath(p) done[p]=true end end @@ -14330,7 +14532,7 @@ function resolvers.registerextrapath(paths,subpaths) local ps=ep[i].."/"..s if not done[ps] then newn=newn+1 - ep[newn]=resolvers.cleanpath(ps) + ep[newn]=cleanpath(ps) done[ps]=true end end @@ -14384,7 +14586,7 @@ function resolvers.cleanpathlist(str) local t=resolvers.expandedpathlist(str) if t then for i=1,#t do - t[i]=collapsepath(resolvers.cleanpath(t[i])) + t[i]=collapsepath(cleanpath(t[i])) end end return t @@ -14434,7 +14636,7 @@ function resolvers.registerfilehash(name,content,someerror) end end local function isreadable(name) - local readable=lfs.isfile(name) + local readable=isfile(name) if trace_detail then if readable then report_resolving("file %a is readable",name) @@ -14445,69 +14647,56 @@ local function isreadable(name) return readable end local function collect_files(names) - local filelist,noffiles={},0 + local filelist={} + local noffiles=0 + local function check(hash,root,pathname,path,name) + if not pathname or find(path,pathname) then + local variant=hash.type + local search=filejoin(root,path,name) + local result=methodhandler('concatinators',variant,root,path,name) + if trace_detail then + report_resolving("match: variant %a, search %a, result %a",variant,search,result) + end + noffiles=noffiles+1 + filelist[noffiles]={ variant,search,result } + end + end for k=1,#names do - local fname=names[k] + local filename=names[k] if trace_detail then - report_resolving("checking name %a",fname) + report_resolving("checking name %a",filename) end - local bname=filebasename(fname) - local dname=filedirname(fname) - if dname=="" or find(dname,"^%.") then - dname=false + local basename=filebasename(filename) + local pathname=filedirname(filename) + if pathname=="" or find(pathname,"^%.") then + pathname=false else - dname=gsub(dname,"%*",".*") - dname="/"..dname.."$" + pathname=gsub(pathname,"%*",".*") + pathname="/"..pathname.."$" end local hashes=instance.hashes for h=1,#hashes do local hash=hashes[h] - local blobpath=hash.name - local files=blobpath and instance.files[blobpath] - if files then + local hashname=hash.name + local content=hashname and instance.files[hashname] + if content then if trace_detail then - report_resolving("deep checking %a, base %a, pattern %a",blobpath,bname,dname) - 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 + report_resolving("deep checking %a, base %a, pattern %a",blobpath,basename,pathname) end - if blobfile then - local blobroot=files.__path__ or blobpath - if type(blobfile)=='string' then - if not dname or find(blobfile,dname) then - local variant=hash.type - local search=filejoin(blobroot,blobfile,bname) - local result=methodhandler('concatinators',hash.type,blobroot,blobfile,bname) - if trace_detail then - report_resolving("match: variant %a, search %a, result %a",variant,search,result) - end - noffiles=noffiles+1 - filelist[noffiles]={ variant,search,result } - end + local path,name=lookup(content,basename) + if path then + local metadata=content.metadata + local realroot=metadata and metadata.path or hashname + if type(path)=="string" then + check(hash,realroot,pathname,path,name) else - for kk=1,#blobfile do - local vv=blobfile[kk] - if not dname or find(vv,dname) then - local variant=hash.type - local search=filejoin(blobroot,vv,bname) - local result=methodhandler('concatinators',hash.type,blobroot,vv,bname) - if trace_detail then - report_resolving("match: variant %a, search %a, result %a",variant,search,result) - end - noffiles=noffiles+1 - filelist[noffiles]={ variant,search,result } - end + for i=1,#path do + check(hash,realroot,pathname,path[i],name) end end end elseif trace_locating then - report_resolving("no match in %a (%s)",blobpath,bname) + report_resolving("no match in %a (%s)",hashname,basename) end end end @@ -14532,7 +14721,7 @@ end local function can_be_dir(name) local fakepaths=instance.fakepaths if not fakepaths[name] then - if lfs.isdir(name) then + if isdir(name) then fakepaths[name]=1 else fakepaths[name]=2 @@ -14548,10 +14737,11 @@ local function find_analyze(filename,askedformat,allresults) if askedformat=="" then if ext=="" or not suffixmap[ext] then local defaultsuffixes=resolvers.defaultsuffixes + local formatofsuffix=resolvers.formatofsuffix for i=1,#defaultsuffixes do local forcedname=filename..'.'..defaultsuffixes[i] wantedfiles[#wantedfiles+1]=forcedname - filetype=resolvers.formatofsuffix(forcedname) + filetype=formatofsuffix(forcedname) if trace_locating then report_resolving("forcing filetype %a",filetype) end @@ -14591,14 +14781,14 @@ local function find_wildcard(filename,allresults) if trace_locating then report_resolving("checking wildcard %a",filename) end - local method,result=resolvers.findwildcardfiles(filename) + local result=resolvers.findwildcardfiles(filename) if result then return "wildcard",result end end end local function find_qualified(filename,allresults,askedformat,alsostripped) - if not file.is_qualified_path(filename) then + if not is_qualified_path(filename) then return end if trace_locating then @@ -14687,7 +14877,6 @@ local function find_intree(filename,filetype,wantedfiles,allresults) if trace_detail then report_resolving("checking filename %a",filename) end - local resolve=resolvers.resolve local result={} for k=1,#pathlist do local path=pathlist[k] @@ -14706,8 +14895,8 @@ local function find_intree(filename,filetype,wantedfiles,allresults) local fl=filelist[k] local f=fl[2] local d=dirlist[k] - if find(d,expression) or find(resolve(d),expression) then - result[#result+1]=resolve(fl[3]) + if find(d,expression) or find(resolveprefix(d),expression) then + result[#result+1]=resolveprefix(fl[3]) done=true if allresults then if trace_detail then @@ -14729,7 +14918,7 @@ local function find_intree(filename,filetype,wantedfiles,allresults) else method="filesystem" pathname=gsub(pathname,"/+$","") - pathname=resolve(pathname) + pathname=resolveprefix(pathname) local scheme=url.hasscheme(pathname) if not scheme or scheme=="file" then local pname=gsub(pathname,"%.%*$",'') @@ -14819,7 +15008,7 @@ local function find_otherwise(filename,filetype,wantedfiles,allresults) local filelist=collect_files(wantedfiles) local fl=filelist and filelist[1] if fl then - return "otherwise",{ resolvers.resolve(fl[3]) } + return "otherwise",{ resolveprefix(fl[3]) } end end collect_instance_files=function(filename,askedformat,allresults) @@ -14919,39 +15108,30 @@ function resolvers.findpath(filename,filetype) return filedirname(findfiles(filename,filetype,false)[1] or "") end local function findgivenfiles(filename,allresults) - local bname,result=filebasename(filename),{} + local base=filebasename(filename) + local result={} local hashes=instance.hashes - local noffound=0 + local function okay(hash,path,name) + local found=methodhandler('concatinators',hash.type,hash.name,path,name) + if found and found~="" then + result[#result+1]=resolveprefix(found) + return not allresults + end + end for k=1,#hashes do local hash=hashes[k] - local files=instance.files[hash.name] 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 - local found=methodhandler('concatinators',hash.type,hash.name,blist,bname) or "" - if found~="" then - noffound=noffound+1 - result[noffound]=resolvers.resolve(found) - if not allresults then - break - end + local content=instance.files[hash.name] + if content then + local path,name=lookup(content,base) + if not path then + elseif type(path)=="string" then + if okay(hash,path,name) then + return result end else - for kk=1,#blist do - local vv=blist[kk] - local found=methodhandler('concatinators',hash.type,hash.name,vv,bname) or "" - if found~="" then - noffound=noffound+1 - result[noffound]=resolvers.resolve(found) - if not allresults then break end + for i=1,#path do + if okay(hash,path[i],name) then + return result end end end @@ -14965,64 +15145,80 @@ end function resolvers.findgivenfile(filename) return findgivenfiles(filename,false)[1] or "" end -local function doit(path,blist,bname,tag,variant,result,allresults) - local done=false - if blist and variant then - local resolve=resolvers.resolve - if type(blist)=='string' then - if find(lower(blist),path) then - local full=methodhandler('concatinators',variant,tag,blist,bname) or "" - result[#result+1]=resolve(full) - done=true - end - else - for kk=1,#blist do - local vv=blist[kk] - if find(lower(vv),path) then - local full=methodhandler('concatinators',variant,tag,vv,bname) or "" - result[#result+1]=resolve(full) - done=true - if not allresults then break end - end - end - end - end - return done -end local makewildcard=Cs( (P("^")^0*P("/")*P(-1)+P(-1))/".*"+(P("^")^0*P("/")/"")^0*(P("*")/".*"+P("-")/"%%-"+P(".")/"%%."+P("?")/"."+P("\\")/"/"+P(1))^0 ) function resolvers.wildcardpattern(pattern) return lpegmatch(makewildcard,pattern) or pattern end -local function findwildcardfiles(filename,allresults,result) - result=result or {} +local function findwildcardfiles(filename,allresults,result) + local result=result or {} local base=filebasename(filename) local dirn=filedirname(filename) local path=lower(lpegmatch(makewildcard,dirn) or dirn) local name=lower(lpegmatch(makewildcard,base) or base) - local files,done=instance.files,false + local files=instance.files if find(name,"*",1,true) then local hashes=instance.hashes + local function okay(found,path,base,hashname,hashtype) + if find(found,path) then + local full=methodhandler('concatinators',hashtype,hashname,found,base) + if full and full~="" then + result[#result+1]=resolveprefix(full) + return not allresults + end + end + end for k=1,#hashes do local hash=hashes[k] - local hashname,hashtype=hash.name,hash.type - for kk,hh in next,files[hashname] do - if not find(kk,"^remap:") then - if find(lower(kk),name) then - if doit(path,hh,kk,hashname,hashtype,result,allresults) then done=true end - if done and not allresults then break end + local hashname=hash.name + local hashtype=hash.type + if hashname and hashtype then + for found,base in filtered(files[hashname],name) do + if type(found)=='string' then + if okay(found,path,base,hashname,hashtype) then + break + end + else + for i=1,#found do + if okay(found[i],path,base,hashname,hashtype) then + break + end + end end end end end else + local function okayokay(found,path,base,hashname,hashtype) + if find(found,path) then + local full=methodhandler('concatinators',hashtype,hashname,found,base) + if full and full~="" then + result[#result+1]=resolveprefix(full) + return not allresults + end + end + end local hashes=instance.hashes for k=1,#hashes do local hash=hashes[k] - local hashname,hashtype=hash.name,hash.type - if doit(path,files[hashname][base],base,hashname,hashtype,result,allresults) then done=true end - if done and not allresults then break end + local hashname=hash.name + local hashtype=hash.type + if hashname and hashtype then + local found,base=lookup(content,base) + if not found then + elseif type(found)=='string' then + if okay(found,path,base,hashname,hashtype) then + break + end + else + for i=1,#found do + if okay(found[i],path,base,hashname,hashtype) then + break + end + end + end + end end end return result @@ -15095,7 +15291,7 @@ end function resolvers.dowithpath(name,func) local pathlist=resolvers.expandedpathlist(name) for i=1,#pathlist do - func("^"..resolvers.cleanpath(pathlist[i])) + func("^"..cleanpath(pathlist[i])) end end function resolvers.dowithvariable(name,func) @@ -15103,23 +15299,23 @@ function resolvers.dowithvariable(name,func) end function resolvers.locateformat(name) local engine=environment.ownmain or "luatex" - local barename=file.removesuffix(name) - local fullname=file.addsuffix(barename,"fmt") + local barename=removesuffix(name) + local fullname=addsuffix(barename,"fmt") local fmtname=caches.getfirstreadablefile(fullname,"formats",engine) or "" if fmtname=="" then fmtname=resolvers.findfile(fullname) - fmtname=resolvers.cleanpath(fmtname) + fmtname=cleanpath(fmtname) end if fmtname~="" then - local barename=file.removesuffix(fmtname) - local luaname=file.addsuffix(barename,luasuffixes.lua) - local lucname=file.addsuffix(barename,luasuffixes.luc) - local luiname=file.addsuffix(barename,luasuffixes.lui) - if lfs.isfile(luiname) then + local barename=removesuffix(fmtname) + local luaname=addsuffix(barename,luasuffixes.lua) + local lucname=addsuffix(barename,luasuffixes.luc) + local luiname=addsuffix(barename,luasuffixes.lui) + if isfile(luiname) then return barename,luiname - elseif lfs.isfile(lucname) then + elseif isfile(lucname) then return barename,lucname - elseif lfs.isfile(luaname) then + elseif isfile(luaname) then return barename,luaname end end @@ -15141,29 +15337,24 @@ function resolvers.dowithfilesintree(pattern,handle,before,after) local hash=hashes[i] local blobtype=hash.type local blobpath=hash.name - if blobpath then + if blobtype and blobpath then + local total=0 + local checked=0 + local done=0 if before then before(blobtype,blobpath,pattern) end - local files=instance.files[blobpath] - local total,checked,done=0,0,0 - if files then - for k,v in table.sortedhash(files) do - total=total+1 - if find(k,"^remap:") then - elseif find(k,pattern) then - if type(v)=="string" then - checked=checked+1 - if handle(blobtype,blobpath,v,k) then - done=done+1 - end - else - checked=checked+#v - for i=1,#v do - if handle(blobtype,blobpath,v[i],k) then - done=done+1 - end - end + for path,name in filtered(instance.files[blobpath],pattern) do + if type(path)=="string" then + checked=checked+1 + if handle(blobtype,blobpath,path,name) then + done=done+1 + end + else + checked=checked+#path + for i=1,#path do + if handle(blobtype,blobpath,path[i],name) then + done=done+1 end end end @@ -15174,8 +15365,8 @@ function resolvers.dowithfilesintree(pattern,handle,before,after) end end end -resolvers.obsolete=resolvers.obsolete or {} -local obsolete=resolvers.obsolete +local obsolete=resolvers.obsolete or {} +resolvers.obsolete=obsolete resolvers.find_file=resolvers.findfile obsolete.find_file=resolvers.findfile resolvers.find_files=resolvers.findfiles obsolete.find_files=resolvers.findfiles @@ -15186,7 +15377,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-pre"] = package.loaded["data-pre"] or true --- original size: 6643, stripped down to: 4401 +-- original size: 3106, stripped down to: 2563 if not modules then modules={} end modules ['data-pre']={ version=1.001, @@ -15196,44 +15387,51 @@ if not modules then modules={} end modules ['data-pre']={ license="see context related readme files" } local resolvers=resolvers -local prefixes=utilities.storage.allocate() -resolvers.prefixes=prefixes -local cleanpath,findgivenfile,expansion=resolvers.cleanpath,resolvers.findgivenfile,resolvers.expansion +local prefixes=resolvers.prefixes +local cleanpath=resolvers.cleanpath +local findgivenfile=resolvers.findgivenfile +local expansion=resolvers.expansion local getenv=resolvers.getenv -local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match -local joinpath,basename,dirname=file.join,file.basename,file.dirname -local getmetatable,rawset,type=getmetatable,rawset,type +local basename=file.basename +local dirname=file.dirname +local joinpath=file.join +local isfile=lfs.isfile prefixes.environment=function(str) return cleanpath(expansion(str)) end -prefixes.relative=function(str,n) - if io.exists(str) then - elseif io.exists("./"..str) then - str="./"..str - else - local p="../" - for i=1,n or 2 do - if io.exists(p..str) then - str=p..str - break - else - p=p.."../" +local function relative(str,n) + if not isfile(str) then + local pstr="./"..str + if isfile(pstr) then + str=pstr + else + local p="../" + for i=1,n or 2 do + local pstr=p..str + if isfile(pstr) then + str=pstr + break + else + p=p.."../" + end end end end return cleanpath(str) end +local function locate(str) + local fullname=findgivenfile(str) or "" + return cleanpath(fullname~="" and fullname or str) +end +prefixes.relative=relative +prefixes.locate=locate prefixes.auto=function(str) - local fullname=prefixes.relative(str) - if not lfs.isfile(fullname) then - fullname=prefixes.locate(str) + local fullname=relative(str) + if not isfile(fullname) then + fullname=locate(str) end return fullname end -prefixes.locate=function(str) - local fullname=findgivenfile(str) or "" - return cleanpath((fullname~="" and fullname) or str) -end prefixes.filename=function(str) local fullname=findgivenfile(str) or "" return cleanpath(basename((fullname~="" and fullname) or str)) @@ -15277,87 +15475,6 @@ prefixes.kpse=prefixes.locate prefixes.full=prefixes.locate prefixes.file=prefixes.filename prefixes.path=prefixes.pathname -function resolvers.allprefixes(separator) - local all=table.sortedkeys(prefixes) - if separator then - for i=1,#all do - all[i]=all[i]..":" - end - end - return all -end -local function _resolve_(method,target) - local action=prefixes[method] - if action then - return action(target) - else - return method..":"..target - end -end -local resolved,abstract={},{} -function resolvers.resetresolve(str) - resolved,abstract={},{} -end -local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) -local prefix=C(R("az")^2)*P(":") -local target=C((1-S(" \"\';,"))^1) -local notarget=(#S(";,")+P(-1))*Cc("") -local pattern=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) -local function resolve(str) - if type(str)=="table" then - local t={} - for i=1,#str do - t[i]=resolve(str[i]) - end - return t - else - local res=resolved[str] - if not res then - res=lpegmatch(pattern,str) - resolved[str]=res - abstract[res]=str - end - return res - end -end -local function unresolve(str) - return abstract[str] or str -end -resolvers.resolve=resolve -resolvers.unresolve=unresolve -if type(os.uname)=="function" then - for k,v in next,os.uname() do - if not prefixes[k] then - prefixes[k]=function() return v end - end - end -end -if os.type=="unix" then - local pattern - local function makepattern(t,k,v) - if t then - rawset(t,k,v) - end - local colon=P(":") - for k,v in table.sortedpairs(prefixes) do - if p then - p=P(k)+p - else - p=P(k) - end - end - pattern=Cs((p*colon+colon/";"+P(1))^0) - end - makepattern() - getmetatable(prefixes).__newindex=makepattern - function resolvers.repath(str) - return lpegmatch(pattern,str) - end -else - function resolvers.repath(str) - return str - end -end end -- of closure @@ -15419,7 +15536,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-fil"] = package.loaded["data-fil"] or true --- original size: 3801, stripped down to: 3231 +-- original size: 3863, stripped down to: 3310 if not modules then modules={} end modules ['data-fil']={ version=1.001, @@ -15431,30 +15548,31 @@ if not modules then modules={} end modules ['data-fil']={ local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_files=logs.reporter("resolvers","files") local resolvers=resolvers +local resolveprefix=resolvers.resolve local finders,openers,loaders,savers=resolvers.finders,resolvers.openers,resolvers.loaders,resolvers.savers local locators,hashers,generators,concatinators=resolvers.locators,resolvers.hashers,resolvers.generators,resolvers.concatinators local checkgarbage=utilities.garbagecollector and utilities.garbagecollector.check function locators.file(specification) - local name=specification.filename - local realname=resolvers.resolve(name) + local filename=specification.filename + local realname=resolveprefix(filename) if realname and realname~='' and lfs.isdir(realname) then if trace_locating then - report_files("file locator %a found as %a",name,realname) + report_files("file locator %a found as %a",filename,realname) end - resolvers.appendhash('file',name,true) + resolvers.appendhash('file',filename,true) elseif trace_locating then - report_files("file locator %a not found",name) + report_files("file locator %a not found",filename) end end function hashers.file(specification) - local name=specification.filename - local content=caches.loadcontent(name,'files') - resolvers.registerfilehash(name,content,content==nil) + local pathname=specification.filename + local content=caches.loadcontent(pathname,'files') + resolvers.registerfilehash(pathname,content,content==nil) end function generators.file(specification) - local path=specification.filename - local content=resolvers.scanfiles(path,false,true) - resolvers.registerfilehash(path,content,true) + local pathname=specification.filename + local content=resolvers.scanfiles(pathname,false,true) + resolvers.registerfilehash(pathname,content,true) end concatinators.file=file.join function finders.file(specification,filetype) @@ -15736,7 +15854,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-zip"] = package.loaded["data-zip"] or true --- original size: 8489, stripped down to: 6757 +-- original size: 9043, stripped down to: 7073 if not modules then modules={} end modules ['data-zip']={ version=1.001, @@ -15779,7 +15897,7 @@ function zip.openarchive(name) local arch=archives[name] if not arch then local full=resolvers.findfile(name) or "" - arch=(full~="" and zip.open(full)) or false + arch=full~="" and zip.open(full) or false archives[name]=arch end return arch @@ -15938,31 +16056,42 @@ function resolvers.usezipfile(archive) end end function resolvers.registerzipfile(z,tree) - local files,filter={},"" - if tree=="" then - filter="^(.+)/(.-)$" - else - filter=format("^%s/(.+)/(.-)$",tree) - end + local names={} + local files={} + local remap={} + local n=0 + local filter=tree=="" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree) + local register=resolvers.registerfile if trace_locating then report_zip("registering: using filter %a",filter) end - local register,n=resolvers.registerfile,0 for i in z:files() do - local path,name=match(i.filename,filter) - if path then - if name and name~='' then - register(files,name,path) - n=n+1 - else + local filename=i.filename + local path,name=match(filename,filter) + if not path then + n=n+1 + register(names,filename,"") + local usedname=lower(filename) + files[usedname]="" + if usedname~=filename then + remap[usedname]=filename end - else - register(files,i.filename,'') + elseif name and name~="" then n=n+1 + register(names,name,path) + local usedname=lower(name) + files[usedname]=path + if usedname~=name then + remap[usedname]=name + end + else end end report_zip("registering: %s files registered",n) - return files + return { + files=files, + remap=remap, + } end @@ -15972,7 +16101,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tre"] = package.loaded["data-tre"] or true --- original size: 2508, stripped down to: 2074 +-- original size: 4859, stripped down to: 3335 if not modules then modules={} end modules ['data-tre']={ version=1.001, @@ -15981,42 +16110,50 @@ if not modules then modules={} end modules ['data-tre']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local find,gsub,format=string.find,string.gsub,string.format +local find,gsub,lower=string.find,string.gsub,string.lower +local basename,dirname,joinname=file.basename,file.dirname,file .join +local globdir,isdir=dir.glob,lfs.isdir local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_trees=logs.reporter("resolvers","trees") local resolvers=resolvers -local done,found,notfound={},{},resolvers.finders.notfound -function resolvers.finders.tree(specification) +local resolveprefix=resolvers.resolve +local notfound=resolvers.finders.notfound +local collectors={} +local found={} +function resolvers.finders.tree(specification) local spec=specification.filename - local fnd=found[spec] - if fnd==nil then + local okay=found[spec] + if okay==nil then if spec~="" then - local path,name=file.dirname(spec),file.basename(spec) - if path=="" then path="." end - local hash=done[path] - if not hash then - local pattern=path.."/*" - hash=dir.glob(pattern) - done[path]=hash + local path=dirname(spec) + local name=basename(spec) + if path=="" then + path="." + end + local names=collectors[path] + if not names then + local pattern=find(path,"/%*+$") and path or (path.."/*") + names=globdir(pattern) + collectors[path]=names end local pattern="/"..gsub(name,"([%.%-%+])","%%%1").."$" - for k=1,#hash do - local v=hash[k] - if find(v,pattern) then - found[spec]=v - return v + for i=1,#names do + local fullname=names[i] + if find(fullname,pattern) then + found[spec]=fullname + return fullname end end end - fnd=notfound() - found[spec]=fnd + okay=notfound() + found[spec]=okay end - return fnd + return okay end function resolvers.locators.tree(specification) local name=specification.filename - local realname=resolvers.resolve(name) - if realname and realname~='' and lfs.isdir(realname) then + local realname=resolveprefix(name) + if realname and realname~='' and isdir(realname) then if trace_locating then report_trees("locator %a found",realname) end @@ -16033,10 +16170,43 @@ function resolvers.hashers.tree(specification) resolvers.methodhandler("hashers",name) resolvers.generators.file(specification) end -resolvers.concatinators.tree=resolvers.concatinators.file -resolvers.generators.tree=resolvers.generators.file -resolvers.openers.tree=resolvers.openers.file -resolvers.loaders.tree=resolvers.loaders.file +local collectors={} +table.setmetatableindex(collectors,function(t,k) + local rootname=gsub(k,"[/%*]+$","") + local dataname=joinname(rootname,"dirlist") + local data=caches.loadcontent(dataname,"files",dataname) + local content=data and data.content + local lookup=resolvers.get_from_content + if not content then + content=resolvers.scanfiles(rootname) + caches.savecontent(dataname,"files",content,dataname) + end + local files=content.files + local v=function(filename) + local path,name=lookup(content,filename) + if not path then + return filename + elseif type(path)=="table" then + path=path[1] + end + return joinname(rootname,path,name) + end + t[k]=v + return v +end) +function resolvers.finders.dirlist(specification) + local spec=specification.filename + if spec~="" then + local path,name=dirname(spec),basename(spec) + return path and collectors[path](name) or notfound() + end + return notfound() +end +resolvers.locators .dirlist=resolvers.locators .tree +resolvers.hashers .dirlist=resolvers.hashers .tree +resolvers.generators.dirlist=resolvers.generators.file +resolvers.openers .dirlist=resolvers.openers .file +resolvers.loaders .dirlist=resolvers.loaders .file end -- of closure @@ -16221,7 +16391,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-lua"] = package.loaded["data-lua"] or true --- original size: 4237, stripped down to: 3177 +-- original size: 4313, stripped down to: 3227 if not modules then modules={} end modules ['data-lua']={ version=1.001, @@ -16230,7 +16400,7 @@ if not modules then modules={} end modules ['data-lua']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local resolvers,package=resolvers,package +local package,lpeg=package,lpeg local gsub=string.gsub local concat=table.concat local addsuffix=file.addsuffix @@ -16241,9 +16411,11 @@ local luaformats={ 'TEXINPUTS','LUAINPUTS' } local libformats={ 'CLUAINPUTS' } local helpers=package.helpers or {} local methods=helpers.methods or {} +local resolvers=resolvers +local resolveprefix=resolvers.resolve +helpers.report=logs.reporter("resolvers","libraries") trackers.register("resolvers.libraries",function(v) helpers.trace=v end) trackers.register("resolvers.locating",function(v) helpers.trace=v end) -helpers.report=logs.reporter("resolvers","libraries") helpers.sequence={ "already loaded", "preload table", @@ -16258,7 +16430,7 @@ helpers.sequence={ } local pattern=Cs(P("!")^0/""*(P("/")*P(-1)/"/"+P("/")^1/"/"+1)^0) function helpers.cleanpath(path) - return resolvers.resolve(lpegmatch(pattern,path)) + return resolveprefix(lpegmatch(pattern,path)) end local loadedaslib=helpers.loadedaslib local getextraluapaths=package.extraluapaths @@ -16395,7 +16567,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tmf"] = package.loaded["data-tmf"] or true --- original size: 2600, stripped down to: 1627 +-- original size: 2601, stripped down to: 1627 if not modules then modules={} end modules ['data-tmf']={ version=1.001, @@ -16451,7 +16623,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-lst"] = package.loaded["data-lst"] or true --- original size: 2654, stripped down to: 2301 +-- original size: 2734, stripped down to: 2354 if not modules then modules={} end modules ['data-lst']={ version=1.001, @@ -16460,10 +16632,13 @@ if not modules then modules={} end modules ['data-lst']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local find,concat,upper,format=string.find,table.concat,string.upper,string.format +local rawget,type,next=rawget,type,next +local find,concat,upper=string.find,table.concat,string.upper local fastcopy,sortedpairs=table.fastcopy,table.sortedpairs -resolvers.listers=resolvers.listers or {} local resolvers=resolvers +local listers=resolvers.listers or {} +resolvers.listers=listers +local resolveprefix=resolvers.resolve local report_lists=logs.reporter("resolvers","lists") local function tabstr(str) if type(str)=='table' then @@ -16472,7 +16647,7 @@ local function tabstr(str) return str end end -function resolvers.listers.variables(pattern) +function listers.variables(pattern) local instance=resolvers.instance local environment=instance.environment local variables=instance.variables @@ -16493,10 +16668,10 @@ function resolvers.listers.variables(pattern) for key,value in sortedpairs(configured) do if key~="" and (pattern=="" or find(upper(key),pattern)) then report_lists(key) - report_lists(" env: %s",tabstr(rawget(environment,key)) or "unset") - report_lists(" var: %s",tabstr(configured[key]) or "unset") - report_lists(" exp: %s",tabstr(expansions[key]) or "unset") - report_lists(" res: %s",tabstr(resolvers.resolve(expansions[key])) or "unset") + report_lists(" env: %s",tabstr(rawget(environment,key)) or "unset") + report_lists(" var: %s",tabstr(configured[key]) or "unset") + report_lists(" exp: %s",tabstr(expansions[key]) or "unset") + report_lists(" res: %s",tabstr(resolveprefix(expansions[key])) or "unset") end end instance.environment=fastcopy(env) @@ -16504,15 +16679,15 @@ function resolvers.listers.variables(pattern) instance.expansions=fastcopy(exp) end local report_resolved=logs.reporter("system","resolved") -function resolvers.listers.configurations() +function listers.configurations() local configurations=resolvers.instance.specification for i=1,#configurations do - report_resolved("file : %s",resolvers.resolve(configurations[i])) + report_resolved("file : %s",resolveprefix(configurations[i])) end report_resolved("") local list=resolvers.expandedpathfromlist(resolvers.splitpath(resolvers.luacnfspec)) for i=1,#list do - local li=resolvers.resolve(list[i]) + local li=resolveprefix(list[i]) if lfs.isdir(li) then report_resolved("path - %s",li) else @@ -16951,8 +17126,8 @@ end -- of closure -- used libraries : l-lua.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-sto.lua util-prs.lua util-fmt.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-mrg.lua util-tpl.lua util-env.lua luat-env.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua util-lib.lua luat-sta.lua luat-fmt.lua -- skipped libraries : - --- original bytes : 699655 --- stripped bytes : 249540 +-- original bytes : 704727 +-- stripped bytes : 250243 -- end library merge diff --git a/scripts/context/stubs/win64/mtxrun.lua b/scripts/context/stubs/win64/mtxrun.lua index 189fc4b7b..70f493525 100644 --- a/scripts/context/stubs/win64/mtxrun.lua +++ b/scripts/context/stubs/win64/mtxrun.lua @@ -1195,7 +1195,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-table"] = package.loaded["l-table"] or true --- original size: 31828, stripped down to: 20814 +-- original size: 33243, stripped down to: 21578 if not modules then modules={} end modules ['l-table']={ version=1.001, @@ -1342,14 +1342,14 @@ local function sortedhash(t,cmp) end local n=0 local m=#s - local function kv(s) + local function kv() if n<m then n=n+1 local k=s[n] return k,t[k] end end - return kv,s + return kv else return nothing end @@ -2110,6 +2110,44 @@ function table.values(t,s) return {} end end +function table.filtered(t,pattern,sort,cmp) + if t and type(pattern)=="string" then + if sort then + local s + if cmp then + s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) + else + s=sortedkeys(t) + end + local n=0 + local m=#s + local function kv(s) + while n<m do + n=n+1 + local k=s[n] + if find(k,pattern) then + return k,t[k] + end + end + end + return kv,s + else + local n=next(t) + local function iterator() + while n do + local k=n + n=next(t,k) + if find(k,pattern) then + return k,t[k] + end + end + end + return iterator,t + end + else + return nothing + end +end end -- of closure @@ -3775,7 +3813,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-dir"] = package.loaded["l-dir"] or true --- original size: 14788, stripped down to: 9096 +-- original size: 16056, stripped down to: 10707 if not modules then modules={} end modules ['l-dir']={ version=1.001, @@ -3785,7 +3823,7 @@ if not modules then modules={} end modules ['l-dir']={ license="see context related readme files" } local type,select=type,select -local find,gmatch,match,gsub=string.find,string.gmatch,string.match,string.gsub +local find,gmatch,match,gsub,sub=string.find,string.gmatch,string.match,string.gsub,string.sub local concat,insert,remove,unpack=table.concat,table.insert,table.remove,table.unpack local lpegmatch=lpeg.match 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 @@ -3794,54 +3832,123 @@ local dir=dir local lfs=lfs local attributes=lfs.attributes local walkdir=lfs.dir -local isdir=lfs.isdir -local isfile=lfs.isfile +local isdir=lfs.isdir +local isfile=lfs.isfile local currentdir=lfs.currentdir local chdir=lfs.chdir local mkdir=lfs.mkdir local onwindows=os.type=="windows" or find(os.getenv("PATH"),";",1,true) -if not isdir then - function isdir(name) - local a=attributes(name) - return a and a.mode=="directory" +if onwindows then + isdir=function(name) + name=gsub(name,"([/\\]+)$","/.") + return attributes(name,"mode")=="directory" + end + isfile=function(name) + return attributes(name,"mode")=="file" end lfs.isdir=isdir -end -if not isfile then - function isfile(name) - local a=attributes(name) - return a and a.mode=="file" + lfs.isfile=isfile +else + isdir=function(name) + return attributes(name,"mode")=="directory" + end + isfile=function(name) + return attributes(name,"mode")=="file" end + lfs.isdir=isdir lfs.isfile=isfile end function dir.current() return (gsub(currentdir(),"\\","/")) end -local lfsisdir=isdir -local function isdir(path) - path=gsub(path,"[/\\]+$","") - return lfsisdir(path) +local function glob_pattern_function(path,patt,recurse,action) + if isdir(path) then + local usedpath + if path=="/" then + usedpath="/." + elseif not find(path,"/$") then + usedpath=path.."/." + path=path.."/" + else + usedpath=path + end + local dirs + for name in walkdir(usedpath) do + if name~="." and name~=".." then + local full=path..name + local mode=attributes(full,'mode') + if mode=='file' then + if not patt or find(full,patt) then + action(full) + end + elseif recurse and mode=="directory" then + if not dirs then + dirs={ full } + else + dirs[#dirs+1]=full + end + end + end + end + if dirs then + for i=1,#dirs do + glob_pattern_function(dirs[i],patt,recurse,action) + end + end + end end -lfs.isdir=isdir -local function globpattern(path,patt,recurse,action) - if path=="/" then - path=path.."." - elseif not find(path,"/$") then - path=path..'/' - end - if isdir(path) then - for name in walkdir(path) do - local full=path..name - local mode=attributes(full,'mode') - if mode=='file' then - if find(full,patt) then - action(full) +local function glob_pattern_table(path,patt,recurse,result) + if not result then + result={} + end + if isdir(path) then + local usedpath + if path=="/" then + usedpath="/." + elseif not find(path,"/$") then + usedpath=path.."/." + path=path.."/" + else + usedpath=path + end + local dirs + for name in walkdir(usedpath) do + if name~="." and name~=".." then + local full=path..name + local mode=attributes(full,'mode') + if mode=='file' then + if not patt or find(full,patt) then + result[#result+1]=full + end + elseif recurse and mode=="directory" then + if not dirs then + dirs={ full } + else + dirs[#dirs+1]=full + end end - elseif recurse and (mode=="directory") and (name~='.') and (name~="..") then - globpattern(full,patt,recurse,action) + end + end + if dirs then + for i=1,#dirs do + glob_pattern_table(dirs[i],patt,recurse,result) end end end + return result +end +local function globpattern(path,patt,recurse,method) + local kind=type(method) + if pattern and sub(patt,1,-3)==path then + patt=false + end + if kind=="function" then + return glob_pattern_function(path,patt,recurse,method) + elseif kind=="table" then + return glob_pattern_table(path,patt,recurse,method) + else + return glob_pattern_table(path,patt,recurse,{}) + end end dir.globpattern=globpattern local function collectpattern(path,patt,recurse,result) @@ -3853,18 +3960,24 @@ local function collectpattern(path,patt,recurse,result) ok,scanner,first=xpcall(function() return walkdir(path) end,function() end) end if ok and type(scanner)=="function" then - if not find(path,"/$") then path=path..'/' end + if not find(path,"/$") then + path=path..'/' + end for name in scanner,first do - local full=path..name - local attr=attributes(full) - local mode=attr.mode - if mode=='file' then - if find(full,patt) then + if name=="." then + elseif name==".." then + else + 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" then + attr.list=collectpattern(full,patt,recurse) result[name]=attr end - elseif recurse and (mode=="directory") and (name~='.') and (name~="..") then - attr.list=collectpattern(full,patt,recurse) - result[name]=attr end end end @@ -3872,15 +3985,15 @@ local function collectpattern(path,patt,recurse,result) end dir.collectpattern=collectpattern local separator -if onwindows then +if onwindows then local slash=S("/\\")/"/" - pattern=Ct { + pattern={ [1]=(Cs(P(".")+slash^1)+Cs(R("az","AZ")*P(":")*slash^0)+Cc("./"))*V(2)*V(3), [2]=Cs(((1-S("*?/\\"))^0*slash)^0), [3]=Cs(P(1)^0) } -else - pattern=Ct { +else + pattern={ [1]=(C(P(".")+P("/")^1)+Cc("./"))*V(2)*V(3), [2]=C(((1-S("*?/"))^0*P("/"))^0), [3]=C(P(1)^0) @@ -3898,9 +4011,8 @@ local function glob(str,t) elseif 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 root,path,base=lpegmatch(pattern,str) + if root and path and base then local recurse=find(base,"**",1,true) local start=root..path local result=lpegmatch(filter,start..base) @@ -3922,16 +4034,12 @@ local function glob(str,t) return { str } end 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 root,path,base=lpegmatch(pattern,str) + if root and path and base then local recurse=find(base,"**",1,true) local start=root..path local result=lpegmatch(filter,start..base) - globpattern(start,result,recurse,action) - return t + return globpattern(start,result,recurse,t) else return {} end @@ -4879,7 +4987,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-str"] = package.loaded["util-str"] or true --- original size: 33485, stripped down to: 18420 +-- original size: 34240, stripped down to: 18733 if not modules then modules={} end modules ['util-str']={ version=1.001, @@ -5544,6 +5652,15 @@ else add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=lpeg.patterns.texescape }) add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=lpeg.patterns.luaescape }) end +local dquote=patterns.dquote +local equote=patterns.escaped+dquote/'\\"'+1 +local space=patterns.space +local cquote=Cc('"') +local pattern=Cs(dquote*(equote-P(-2))^0*dquote) ++Cs(cquote*(equote-space)^0*space*equote^0*cquote) +function string.optionalquoted(str) + return lpegmatch(pattern,str) or str +end end -- of closure @@ -8717,7 +8834,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-env"] = package.loaded["util-env"] or true --- original size: 8814, stripped down to: 5092 +-- original size: 8022, stripped down to: 5038 if not modules then modules={} end modules ['util-env']={ version=1.001, @@ -8728,7 +8845,7 @@ if not modules then modules={} end modules ['util-env']={ } local allocate,mark=utilities.storage.allocate,utilities.storage.mark local format,sub,match,gsub,find=string.format,string.sub,string.match,string.gsub,string.find -local unquoted,quoted=string.unquoted,string.quoted +local unquoted,quoted,optionalquoted=string.unquoted,string.quoted,string.optionalquoted local concat,insert,remove=table.concat,table.insert,table.remove environment=environment or {} local environment=environment @@ -8841,24 +8958,14 @@ function environment.splitarguments(separator) return before,after end function environment.reconstructcommandline(arg,noquote) + local resolveprefix=resolvers.resolve arg=arg or environment.originalarguments if noquote and #arg==1 then - local a=arg[1] - a=resolvers.resolve(a) - a=unquoted(a) - return a + return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1]) elseif #arg>0 then local result={} for i=1,#arg do - local a=arg[i] - a=resolvers.resolve(a) - a=unquoted(a) - a=gsub(a,'"','\\"') - if find(a," ",1,true) then - result[#result+1]=quoted(a) - else - result[#result+1]=a - end + result[i]=optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix) end return concat(result," ") else @@ -12483,7 +12590,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-ini"] = package.loaded["data-ini"] or true --- original size: 7927, stripped down to: 5528 +-- original size: 10598, stripped down to: 7341 if not modules then modules={} end modules ['data-ini']={ version=1.001, @@ -12492,14 +12599,15 @@ if not modules then modules={} end modules ['data-ini']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files", } +local next,type,getmetatable,rawset=next,type,getmetatable,rawset local gsub,find,gmatch,char=string.gsub,string.find,string.gmatch,string.char -local next,type=next,type local filedirname,filebasename,filejoin=file.dirname,file.basename,file.join +local ostype,osname,osuname,ossetenv,osgetenv=os.type,os.name,os.uname,os.setenv,os.getenv +local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local trace_detail=false trackers.register("resolvers.details",function(v) trace_detail=v end) local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) local report_initialization=logs.reporter("resolvers","initialization") -local ostype,osname,ossetenv,osgetenv=os.type,os.name,os.setenv,os.getenv resolvers=resolvers or {} local resolvers=resolvers texconfig.kpse_init=false @@ -12632,10 +12740,88 @@ if type(profiler)=="table" and not jit then profiler.start("luatex-profile.log") end) end -if not resolvers.resolve then - function resolvers.resolve (s) return s end - function resolvers.unresolve(s) return s end - function resolvers.repath (s) return s end +local prefixes=utilities.storage.allocate() +resolvers.prefixes=prefixes +local resolved={} +local abstract={} +function resolvers.resetresolve(str) + resolved,abstract={},{} +end +function resolvers.allprefixes(separator) + local all=table.sortedkeys(prefixes) + if separator then + for i=1,#all do + all[i]=all[i]..":" + end + end + return all +end +local function _resolve_(method,target) + local action=prefixes[method] + if action then + return action(target) + else + return method..":"..target + end +end +function resolvers.unresolve(str) + return abstract[str] or str +end +local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) +local prefix=C(R("az")^2)*P(":") +local target=C((1-S(" \"\';,"))^1) +local notarget=(#S(";,")+P(-1))*Cc("") +local pattern=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) +local function resolve(str) + if type(str)=="table" then + local res={} + for i=1,#str do + res[i]=resolve(str[i]) + end + return res + else + local res=resolved[str] + if not res then + res=lpegmatch(pattern,str) + resolved[str]=res + abstract[res]=str + end + return res + end +end +resolvers.resolve=resolve +if type(osuname)=="function" then + for k,v in next,osuname() do + if not prefixes[k] then + prefixes[k]=function() return v end + end + end +end +if ostype=="unix" then + local pattern + local function makepattern(t,k,v) + if t then + rawset(t,k,v) + end + local colon=P(":") + for k,v in table.sortedpairs(prefixes) do + if p then + p=P(k)+p + else + p=P(k) + end + end + pattern=Cs((p*colon+colon/";"+P(1))^0) + end + makepattern() + table.setmetatablenewindex(prefixes,makepattern) + function resolvers.repath(str) + return lpegmatch(pattern,str) + end +else + function resolvers.repath(str) + return str + end end @@ -12645,7 +12831,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-exp"] = package.loaded["data-exp"] or true --- original size: 15317, stripped down to: 9723 +-- original size: 16463, stripped down to: 10113 if not modules then modules={} end modules ['data-exp']={ version=1.001, @@ -12660,11 +12846,14 @@ local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns local Ct,Cs,Cc,Carg,P,C,S=lpeg.Ct,lpeg.Cs,lpeg.Cc,lpeg.Carg,lpeg.P,lpeg.C,lpeg.S local type,next=type,next local ostype=os.type -local collapsepath=file.collapsepath +local collapsepath,joinpath,basename=file.collapsepath,file.join,file.basename local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_globbing=true trackers.register("resolvers.globbing",function(v) trace_globbing=v end) local report_expansions=logs.reporter("resolvers","expansions") +local report_globbing=logs.reporter("resolvers","globbing") local resolvers=resolvers +local resolveprefix=resolvers.resolve local function f_both(a,b) local t,n={},0 for sb in gmatch(b,"[^,]+") do @@ -12754,35 +12943,27 @@ function resolvers.expandedpathfromlist(pathlist) end return newlist end -local cleanup=lpeg.replacer { - { "!","" }, - { "\\","/" }, -} -function resolvers.cleanpath(str) - local doslashes=(P("\\")/"/"+1)^0 - local donegation=(P("!")/"" )^0 - local homedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") - if homedir=="~" or homedir=="" or not lfs.isdir(homedir) then - if trace_expansions then - report_expansions("no home dir set, ignoring dependent paths") - end - function resolvers.cleanpath(str) - if not str or find(str,"~",1,true) then - return "" - else - return lpegmatch(cleanup,str) +local usedhomedir=nil +local donegation=(P("!")/"" )^0 +local doslashes=(P("\\")/"/"+1)^0 +local function expandedhome() + if not usedhomedir then + usedhomedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") + if usedhomedir=="~" or usedhomedir=="" or not lfs.isdir(usedhomedir) then + if trace_expansions then + report_expansions("no home dir set, ignoring dependent path using current path") end - end - else - local dohome=((P("~")+P("$HOME"))/homedir)^0 - local cleanup=Cs(donegation*dohome*doslashes) - function resolvers.cleanpath(str) - return str and lpegmatch(cleanup,str) or "" + usedhomedir="." end end - return resolvers.cleanpath(str) + return usedhomedir +end +local dohome=((P("~")+P("$HOME")+P("%HOME%"))/expandedhome)^0 +local cleanup=Cs(donegation*dohome*doslashes) +resolvers.cleanpath=function(str) + return str and lpegmatch(cleanup,str) or "" end -local expandhome=P("~")/"$HOME" +local expandhome=P("~")/"$HOME" local dodouble=P('"')/""*(expandhome+(1-P('"')))^0*P('"')/"" local dosingle=P("'")/""*(expandhome+(1-P("'")))^0*P("'")/"" local dostring=(expandhome+1 )^0 @@ -12834,7 +13015,7 @@ function resolvers.splitpath(str) end function resolvers.joinpath(str) if type(str)=='table' then - return file.joinpath(str) + return joinpath(str) else return str end @@ -12845,35 +13026,54 @@ local timer={} local scanned={} local nofscans=0 local scancache={} -local function scan(files,spec,path,n,m,r) - local full=(path=="" and spec) or (spec..path..'/') +local fullcache={} +local nofsharedscans=0 +local function scan(files,remap,spec,path,n,m,r,onlyone) + local full=path=="" and spec or (spec..path..'/') local dirs={} local nofdirs=0 for name in directory(full) do if not lpegmatch(weird,name) then - local mode=attributes(full..name,'mode') - if mode=='file' then + local mode=attributes(full..name,"mode") + if mode=="file" then n=n+1 - local f=files[name] - if f then - if type(f)=='string' then - files[name]={ f,path } + local lower=lower(name) + local paths=files[lower] + if paths then + if onlyone then else - f[#f+1]=path + if type(paths)=="string" then + files[lower]={ paths,path } + else + paths[#paths+1]=path + end + if name~=lower then + local rl=remap[lower] + if not rl then + remap[lower]=name + r=r+1 + elseif trace_globbing and rl~=name then + report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) + end + end end else - files[name]=path - local lower=lower(name) + files[lower]=path if name~=lower then - files["remap:"..lower]=name - r=r+1 + local rl=remap[lower] + if not rl then + remap[lower]=name + r=r+1 + elseif trace_globbing and rl~=name then + report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) + end end end - elseif mode=='directory' then + elseif mode=="directory" then m=m+1 nofdirs=nofdirs+1 if path~="" then - dirs[nofdirs]=path..'/'..name + dirs[nofdirs]=path.."/"..name else dirs[nofdirs]=name end @@ -12883,107 +13083,52 @@ local function scan(files,spec,path,n,m,r) if nofdirs>0 then sort(dirs) for i=1,nofdirs do - files,n,m,r=scan(files,spec,dirs[i],n,m,r) + files,remap,n,m,r=scan(files,remap,spec,dirs[i],n,m,r,onlyone) end end scancache[sub(full,1,-2)]=files - return files,n,m,r + return files,remap,n,m,r end -local fullcache={} -function resolvers.scanfiles(path,branch,usecache) - statistics.starttiming(timer) - local realpath=resolvers.resolve(path) +function resolvers.scanfiles(path,branch,usecache,onlyonce) + local realpath=resolveprefix(path) if usecache then - local files=fullcache[realpath] - if files then + local content=fullcache[realpath] + if content then if trace_locating then - report_expansions("using caches scan of path %a, branch %a",path,branch or path) + report_expansions("using cached scan of path %a, branch %a",path,branch or path) end - return files + nofsharedscans=nofsharedscans+1 + return content end end + statistics.starttiming(timer) if trace_locating then report_expansions("scanning path %a, branch %a",path,branch or path) end - local files,n,m,r=scan({},realpath..'/',"",0,0,0) - files.__path__=path - files.__files__=n - files.__directories__=m - files.__remappings__=r + local files,remap,n,m,r=scan({},{},realpath..'/',"",0,0,0,onlyonce) + local content={ + metadata={ + path=path, + files=n, + directories=m, + remappings=r, + }, + files=files, + remap=remap, + } if trace_locating then report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r) end if usecache then scanned[#scanned+1]=realpath - fullcache[realpath]=files + fullcache[realpath]=content end nofscans=nofscans+1 statistics.stoptiming(timer) - return files -end -local function simplescan(files,spec,path) - local full=(path=="" and spec) or (spec..path..'/') - local dirs={} - local nofdirs=0 - for name in directory(full) do - if not lpegmatch(weird,name) then - local mode=attributes(full..name,'mode') - if mode=='file' then - if not files[name] then - files[name]=path - end - elseif mode=='directory' then - nofdirs=nofdirs+1 - if path~="" then - dirs[nofdirs]=path..'/'..name - else - dirs[nofdirs]=name - end - end - end - end - if nofdirs>0 then - sort(dirs) - for i=1,nofdirs do - files=simplescan(files,spec,dirs[i]) - end - end - return files + return content end -local simplecache={} -local nofsharedscans=0 function resolvers.simplescanfiles(path,branch,usecache) - statistics.starttiming(timer) - local realpath=resolvers.resolve(path) - if usecache then - local files=simplecache[realpath] - if not files then - files=scancache[realpath] - if files then - nofsharedscans=nofsharedscans+1 - end - end - if files then - if trace_locating then - report_expansions("using caches scan of path %a, branch %a",path,branch or path) - end - return files - end - end - if trace_locating then - report_expansions("scanning path %a, branch %a",path,branch or path) - end - local files=simplescan({},realpath..'/',"") - if trace_locating then - report_expansions("%s files found",table.count(files)) - end - if usecache then - scanned[#scanned+1]=realpath - simplecache[realpath]=files - end - nofscans=nofscans+1 - statistics.stoptiming(timer) - return files + return resolvers.scanfiles(path,branch,usecache,true) end function resolvers.scandata() table.sort(scanned) @@ -12994,6 +13139,49 @@ function resolvers.scandata() paths=scanned, } end +function resolvers.get_from_content(content,path,name) + local files=content.files + if not files then + return + end + local remap=content.remap + if not remap then + return + end + if name then + local used=lower(name) + return path,remap[used] or used + else + local name=path + local used=lower(name) + local path=files[used] + if path then + return path,remap[used] or used + end + end +end +local nothing=function() end +function resolvers.filtered_from_content(content,pattern) + if content and type(pattern)=="string" then + local pattern=lower(pattern) + local files=content.files + local remap=content.remap + if files and remap then + local n=next(files) + local function iterator() + while n do + local k=n + n=next(files,k) + if find(k,pattern) then + return files[k],remap and remap[k] or k + end + end + end + return iterator + end + end + return nothing +end end -- of closure @@ -13272,7 +13460,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tmp"] = package.loaded["data-tmp"] or true --- original size: 15532, stripped down to: 11648 +-- original size: 15681, stripped down to: 11761 if not modules then modules={} end modules ['data-tmp']={ version=1.100, @@ -13291,6 +13479,7 @@ local trace_cache=false trackers.register("resolvers.cache",function(v) trace_ca local report_caches=logs.reporter("resolvers","caches") local report_resolvers=logs.reporter("resolvers","caching") local resolvers=resolvers +local cleanpath=resolvers.cleanpath local directive_cleanup=false directives.register("system.compile.cleanup",function(v) directive_cleanup=v end) local directive_strip=false directives.register("system.compile.strip",function(v) directive_strip=v end) local compile=utilities.lua.compile @@ -13312,7 +13501,7 @@ caches.relocate=false caches.defaults={ "TMPDIR","TEMPDIR","TMP","TEMP","HOME","HOMEPATH" } local writable,readables,usedreadables=nil,{},{} local function identify() - local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") + local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") if texmfcaches then for k=1,#texmfcaches do local cachepath=texmfcaches[k] @@ -13566,10 +13755,12 @@ local content_state={} function caches.contentstate() return content_state or {} end -function caches.loadcontent(cachename,dataname) - local name=caches.hashed(cachename) - local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") - local filename=file.join(path,name) +function caches.loadcontent(cachename,dataname,filename) + if not filename then + local name=caches.hashed(cachename) + local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") + filename=file.join(path,name) + end local blob=loadfile(addsuffix(filename,luasuffixes.luc)) or loadfile(addsuffix(filename,luasuffixes.lua)) if blob then local data=blob() @@ -13601,10 +13792,12 @@ function caches.collapsecontent(content) end end end -function caches.savecontent(cachename,dataname,content) - local name=caches.hashed(cachename) - local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") - local filename=file.join(path,name) +function caches.savecontent(cachename,dataname,content,filename) + if not filename then + local name=caches.hashed(cachename) + local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") + filename=file.join(path,name) + end local luaname=addsuffix(filename,luasuffixes.lua) local lucname=addsuffix(filename,luasuffixes.luc) if trace_locating then @@ -13647,7 +13840,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-met"] = package.loaded["data-met"] or true --- original size: 5460, stripped down to: 4014 +-- original size: 5347, stripped down to: 4015 if not modules then modules={} end modules ['data-met']={ version=1.100, @@ -13675,7 +13868,7 @@ local function splitmethod(filename) if type(filename)=="table" then return filename end - filename=file.collapsepath(filename,".") + filename=file.collapsepath(filename,".") if not find(filename,"://",1,true) then return { scheme="file",path=filename,original=filename,filename=filename } end @@ -13766,7 +13959,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-res"] = package.loaded["data-res"] or true --- original size: 62045, stripped down to: 43116 +-- original size: 61031, stripped down to: 42613 if not modules then modules={} end modules ['data-res']={ version=1.001, @@ -13776,7 +13969,7 @@ if not modules then modules={} end modules ['data-res']={ license="see context related readme files", } local gsub,find,lower,upper,match,gmatch=string.gsub,string.find,string.lower,string.upper,string.match,string.gmatch -local concat,insert,sortedkeys=table.concat,table.insert,table.sortedkeys +local concat,insert,sortedkeys,sortedhash=table.concat,table.insert,table.sortedkeys,table.sortedhash local next,type,rawget=next,type,rawget local os=os local P,S,R,C,Cc,Cs,Ct,Carg=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cc,lpeg.Cs,lpeg.Ct,lpeg.Carg @@ -13785,14 +13978,19 @@ local formatters=string.formatters local filedirname=file.dirname local filebasename=file.basename local suffixonly=file.suffixonly +local addsuffix=file.addsuffix +local removesuffix=file.removesuffix local filejoin=file.join local collapsepath=file.collapsepath local joinpath=file.joinpath +local is_qualified_path=file.is_qualified_path local allocate=utilities.storage.allocate local settings_to_array=utilities.parsers.settings_to_array +local getcurrentdir=lfs.currentdir +local isfile=lfs.isfile +local isdir=lfs.isdir local setmetatableindex=table.setmetatableindex local luasuffixes=utilities.lua.suffixes -local getcurrentdir=lfs.currentdir local trace_locating=false trackers .register("resolvers.locating",function(v) trace_locating=v end) local trace_detail=false trackers .register("resolvers.details",function(v) trace_detail=v end) local trace_expansions=false trackers .register("resolvers.expansions",function(v) trace_expansions=v end) @@ -13803,10 +14001,14 @@ local expandedpathfromlist=resolvers.expandedpathfromlist local checkedvariable=resolvers.checkedvariable local splitconfigurationpath=resolvers.splitconfigurationpath local methodhandler=resolvers.methodhandler +local filtered=resolvers.filtered_from_content +local lookup=resolvers.get_from_content +local cleanpath=resolvers.cleanpath +local resolveprefix=resolvers.resolve local initializesetter=utilities.setters.initialize local ostype,osname,osenv,ossetenv,osgetenv=os.type,os.name,os.env,os.setenv,os.getenv -resolvers.cacheversion='1.0.1' -resolvers.configbanner='' +resolvers.cacheversion="1.100" +resolvers.configbanner="" resolvers.homedir=environment.homedir resolvers.criticalvars=allocate { "SELFAUTOLOC","SELFAUTODIR","SELFAUTOPARENT","TEXMFCNF","TEXMF","TEXOS" } resolvers.luacnfname="texmfcnf.lua" @@ -13833,7 +14035,7 @@ local instance=resolvers.instance or nil function resolvers.setenv(key,value,raw) if instance then instance.environment[key]=value - ossetenv(key,raw and value or resolvers.resolve(value)) + ossetenv(key,raw and value or resolveprefix(value)) end end local function getenv(key) @@ -13847,7 +14049,7 @@ local function getenv(key) end resolvers.getenv=getenv resolvers.env=getenv -local function resolve(k) +local function resolvevariable(k) return instance.expansions[k] end local dollarstripper=lpeg.stripper("$") @@ -13856,19 +14058,19 @@ local backslashswapper=lpeg.replacer("\\","/") local somevariable=P("$")/"" local somekey=C(R("az","AZ","09","__","--")^1) local somethingelse=P(";")*((1-S("!{}/\\"))^1*P(";")/"")+P(";")*(P(";")/"")+P(1) -local variableexpander=Cs((somevariable*(somekey/resolve)+somethingelse)^1 ) +local variableexpander=Cs((somevariable*(somekey/resolvevariable)+somethingelse)^1 ) local cleaner=P("\\")/"/"+P(";")*S("!{}/\\")^0*P(";")^1/";" local variablecleaner=Cs((cleaner+P(1))^0) -local somevariable=R("az","AZ","09","__","--")^1/resolve +local somevariable=R("az","AZ","09","__","--")^1/resolvevariable local variable=(P("$")/"")*(somevariable+(P("{")/"")*somevariable*(P("}")/"")) local variableresolver=Cs((variable+P(1))^0) local function expandedvariable(var) return lpegmatch(variableexpander,var) or var end -function resolvers.newinstance() - if trace_locating then +function resolvers.newinstance() + if trace_locating then report_resolving("creating instance") - end + end local environment,variables,expansions,order=allocate(),allocate(),allocate(),allocate() local newinstance={ environment=environment, @@ -13995,13 +14197,13 @@ local function identify_configuration_files() for i=1,#cnfpaths do local filepath=cnfpaths[i] local filename=collapsepath(filejoin(filepath,luacnfname)) - local realname=resolvers.resolve(filename) + local realname=resolveprefix(filename) if trace_locating then - local fullpath=gsub(resolvers.resolve(collapsepath(filepath)),"//","/") + local fullpath=gsub(resolveprefix(collapsepath(filepath)),"//","/") local weirdpath=find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c",1,true) report_resolving("looking for %a on %s path %a from specification %a",luacnfname,weirdpath and "weird" or "given",fullpath,filepath) end - if lfs.isfile(realname) then + if isfile(realname) then specification[#specification+1]=filename if trace_locating then report_resolving("found configuration file %a",realname) @@ -14023,7 +14225,7 @@ local function load_configuration_files() local filename=specification[i] local pathname=filedirname(filename) local filename=filejoin(pathname,luacnfname) - local realname=resolvers.resolve(filename) + local realname=resolveprefix(filename) local blob=loadfile(realname) if blob then local setups=instance.setups @@ -14031,7 +14233,7 @@ local function load_configuration_files() local parent=data and data.parent if parent then local filename=filejoin(pathname,parent) - local realname=resolvers.resolve(filename) + local realname=resolveprefix(filename) local blob=loadfile(realname) if blob then local parentdata=blob() @@ -14056,7 +14258,7 @@ local function load_configuration_files() elseif variables[k]==nil then if trace_locating and not warning then report_resolving("variables like %a in configuration file %a should move to the 'variables' subtable", - k,resolvers.resolve(filename)) + k,resolveprefix(filename)) warning=true end variables[k]=v @@ -14116,7 +14318,7 @@ local function locate_file_databases() local stripped=lpegmatch(inhibitstripper,path) if stripped~="" then local runtime=stripped==path - path=resolvers.cleanpath(path) + path=cleanpath(path) local spec=resolvers.splitmethod(stripped) if runtime and (spec.noscheme or spec.scheme=="file") then stripped="tree:///"..stripped @@ -14179,8 +14381,8 @@ function resolvers.renew(hashname) report_resolving("identifying tree %a",hashname) end end - local realpath=resolvers.resolve(hashname) - if lfs.isdir(realpath) then + local realpath=resolveprefix(hashname) + if isdir(realpath) then if trace_locating then report_resolving("using path %a",realpath) end @@ -14308,7 +14510,7 @@ function resolvers.registerextrapath(paths,subpaths) local ps=p.."/"..s if not done[ps] then newn=newn+1 - ep[newn]=resolvers.cleanpath(ps) + ep[newn]=cleanpath(ps) done[ps]=true end end @@ -14318,7 +14520,7 @@ function resolvers.registerextrapath(paths,subpaths) local p=paths[i] if not done[p] then newn=newn+1 - ep[newn]=resolvers.cleanpath(p) + ep[newn]=cleanpath(p) done[p]=true end end @@ -14330,7 +14532,7 @@ function resolvers.registerextrapath(paths,subpaths) local ps=ep[i].."/"..s if not done[ps] then newn=newn+1 - ep[newn]=resolvers.cleanpath(ps) + ep[newn]=cleanpath(ps) done[ps]=true end end @@ -14384,7 +14586,7 @@ function resolvers.cleanpathlist(str) local t=resolvers.expandedpathlist(str) if t then for i=1,#t do - t[i]=collapsepath(resolvers.cleanpath(t[i])) + t[i]=collapsepath(cleanpath(t[i])) end end return t @@ -14434,7 +14636,7 @@ function resolvers.registerfilehash(name,content,someerror) end end local function isreadable(name) - local readable=lfs.isfile(name) + local readable=isfile(name) if trace_detail then if readable then report_resolving("file %a is readable",name) @@ -14445,69 +14647,56 @@ local function isreadable(name) return readable end local function collect_files(names) - local filelist,noffiles={},0 + local filelist={} + local noffiles=0 + local function check(hash,root,pathname,path,name) + if not pathname or find(path,pathname) then + local variant=hash.type + local search=filejoin(root,path,name) + local result=methodhandler('concatinators',variant,root,path,name) + if trace_detail then + report_resolving("match: variant %a, search %a, result %a",variant,search,result) + end + noffiles=noffiles+1 + filelist[noffiles]={ variant,search,result } + end + end for k=1,#names do - local fname=names[k] + local filename=names[k] if trace_detail then - report_resolving("checking name %a",fname) + report_resolving("checking name %a",filename) end - local bname=filebasename(fname) - local dname=filedirname(fname) - if dname=="" or find(dname,"^%.") then - dname=false + local basename=filebasename(filename) + local pathname=filedirname(filename) + if pathname=="" or find(pathname,"^%.") then + pathname=false else - dname=gsub(dname,"%*",".*") - dname="/"..dname.."$" + pathname=gsub(pathname,"%*",".*") + pathname="/"..pathname.."$" end local hashes=instance.hashes for h=1,#hashes do local hash=hashes[h] - local blobpath=hash.name - local files=blobpath and instance.files[blobpath] - if files then + local hashname=hash.name + local content=hashname and instance.files[hashname] + if content then if trace_detail then - report_resolving("deep checking %a, base %a, pattern %a",blobpath,bname,dname) - 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 + report_resolving("deep checking %a, base %a, pattern %a",blobpath,basename,pathname) end - if blobfile then - local blobroot=files.__path__ or blobpath - if type(blobfile)=='string' then - if not dname or find(blobfile,dname) then - local variant=hash.type - local search=filejoin(blobroot,blobfile,bname) - local result=methodhandler('concatinators',hash.type,blobroot,blobfile,bname) - if trace_detail then - report_resolving("match: variant %a, search %a, result %a",variant,search,result) - end - noffiles=noffiles+1 - filelist[noffiles]={ variant,search,result } - end + local path,name=lookup(content,basename) + if path then + local metadata=content.metadata + local realroot=metadata and metadata.path or hashname + if type(path)=="string" then + check(hash,realroot,pathname,path,name) else - for kk=1,#blobfile do - local vv=blobfile[kk] - if not dname or find(vv,dname) then - local variant=hash.type - local search=filejoin(blobroot,vv,bname) - local result=methodhandler('concatinators',hash.type,blobroot,vv,bname) - if trace_detail then - report_resolving("match: variant %a, search %a, result %a",variant,search,result) - end - noffiles=noffiles+1 - filelist[noffiles]={ variant,search,result } - end + for i=1,#path do + check(hash,realroot,pathname,path[i],name) end end end elseif trace_locating then - report_resolving("no match in %a (%s)",blobpath,bname) + report_resolving("no match in %a (%s)",hashname,basename) end end end @@ -14532,7 +14721,7 @@ end local function can_be_dir(name) local fakepaths=instance.fakepaths if not fakepaths[name] then - if lfs.isdir(name) then + if isdir(name) then fakepaths[name]=1 else fakepaths[name]=2 @@ -14548,10 +14737,11 @@ local function find_analyze(filename,askedformat,allresults) if askedformat=="" then if ext=="" or not suffixmap[ext] then local defaultsuffixes=resolvers.defaultsuffixes + local formatofsuffix=resolvers.formatofsuffix for i=1,#defaultsuffixes do local forcedname=filename..'.'..defaultsuffixes[i] wantedfiles[#wantedfiles+1]=forcedname - filetype=resolvers.formatofsuffix(forcedname) + filetype=formatofsuffix(forcedname) if trace_locating then report_resolving("forcing filetype %a",filetype) end @@ -14591,14 +14781,14 @@ local function find_wildcard(filename,allresults) if trace_locating then report_resolving("checking wildcard %a",filename) end - local method,result=resolvers.findwildcardfiles(filename) + local result=resolvers.findwildcardfiles(filename) if result then return "wildcard",result end end end local function find_qualified(filename,allresults,askedformat,alsostripped) - if not file.is_qualified_path(filename) then + if not is_qualified_path(filename) then return end if trace_locating then @@ -14687,7 +14877,6 @@ local function find_intree(filename,filetype,wantedfiles,allresults) if trace_detail then report_resolving("checking filename %a",filename) end - local resolve=resolvers.resolve local result={} for k=1,#pathlist do local path=pathlist[k] @@ -14706,8 +14895,8 @@ local function find_intree(filename,filetype,wantedfiles,allresults) local fl=filelist[k] local f=fl[2] local d=dirlist[k] - if find(d,expression) or find(resolve(d),expression) then - result[#result+1]=resolve(fl[3]) + if find(d,expression) or find(resolveprefix(d),expression) then + result[#result+1]=resolveprefix(fl[3]) done=true if allresults then if trace_detail then @@ -14729,7 +14918,7 @@ local function find_intree(filename,filetype,wantedfiles,allresults) else method="filesystem" pathname=gsub(pathname,"/+$","") - pathname=resolve(pathname) + pathname=resolveprefix(pathname) local scheme=url.hasscheme(pathname) if not scheme or scheme=="file" then local pname=gsub(pathname,"%.%*$",'') @@ -14819,7 +15008,7 @@ local function find_otherwise(filename,filetype,wantedfiles,allresults) local filelist=collect_files(wantedfiles) local fl=filelist and filelist[1] if fl then - return "otherwise",{ resolvers.resolve(fl[3]) } + return "otherwise",{ resolveprefix(fl[3]) } end end collect_instance_files=function(filename,askedformat,allresults) @@ -14919,39 +15108,30 @@ function resolvers.findpath(filename,filetype) return filedirname(findfiles(filename,filetype,false)[1] or "") end local function findgivenfiles(filename,allresults) - local bname,result=filebasename(filename),{} + local base=filebasename(filename) + local result={} local hashes=instance.hashes - local noffound=0 + local function okay(hash,path,name) + local found=methodhandler('concatinators',hash.type,hash.name,path,name) + if found and found~="" then + result[#result+1]=resolveprefix(found) + return not allresults + end + end for k=1,#hashes do local hash=hashes[k] - local files=instance.files[hash.name] 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 - local found=methodhandler('concatinators',hash.type,hash.name,blist,bname) or "" - if found~="" then - noffound=noffound+1 - result[noffound]=resolvers.resolve(found) - if not allresults then - break - end + local content=instance.files[hash.name] + if content then + local path,name=lookup(content,base) + if not path then + elseif type(path)=="string" then + if okay(hash,path,name) then + return result end else - for kk=1,#blist do - local vv=blist[kk] - local found=methodhandler('concatinators',hash.type,hash.name,vv,bname) or "" - if found~="" then - noffound=noffound+1 - result[noffound]=resolvers.resolve(found) - if not allresults then break end + for i=1,#path do + if okay(hash,path[i],name) then + return result end end end @@ -14965,64 +15145,80 @@ end function resolvers.findgivenfile(filename) return findgivenfiles(filename,false)[1] or "" end -local function doit(path,blist,bname,tag,variant,result,allresults) - local done=false - if blist and variant then - local resolve=resolvers.resolve - if type(blist)=='string' then - if find(lower(blist),path) then - local full=methodhandler('concatinators',variant,tag,blist,bname) or "" - result[#result+1]=resolve(full) - done=true - end - else - for kk=1,#blist do - local vv=blist[kk] - if find(lower(vv),path) then - local full=methodhandler('concatinators',variant,tag,vv,bname) or "" - result[#result+1]=resolve(full) - done=true - if not allresults then break end - end - end - end - end - return done -end local makewildcard=Cs( (P("^")^0*P("/")*P(-1)+P(-1))/".*"+(P("^")^0*P("/")/"")^0*(P("*")/".*"+P("-")/"%%-"+P(".")/"%%."+P("?")/"."+P("\\")/"/"+P(1))^0 ) function resolvers.wildcardpattern(pattern) return lpegmatch(makewildcard,pattern) or pattern end -local function findwildcardfiles(filename,allresults,result) - result=result or {} +local function findwildcardfiles(filename,allresults,result) + local result=result or {} local base=filebasename(filename) local dirn=filedirname(filename) local path=lower(lpegmatch(makewildcard,dirn) or dirn) local name=lower(lpegmatch(makewildcard,base) or base) - local files,done=instance.files,false + local files=instance.files if find(name,"*",1,true) then local hashes=instance.hashes + local function okay(found,path,base,hashname,hashtype) + if find(found,path) then + local full=methodhandler('concatinators',hashtype,hashname,found,base) + if full and full~="" then + result[#result+1]=resolveprefix(full) + return not allresults + end + end + end for k=1,#hashes do local hash=hashes[k] - local hashname,hashtype=hash.name,hash.type - for kk,hh in next,files[hashname] do - if not find(kk,"^remap:") then - if find(lower(kk),name) then - if doit(path,hh,kk,hashname,hashtype,result,allresults) then done=true end - if done and not allresults then break end + local hashname=hash.name + local hashtype=hash.type + if hashname and hashtype then + for found,base in filtered(files[hashname],name) do + if type(found)=='string' then + if okay(found,path,base,hashname,hashtype) then + break + end + else + for i=1,#found do + if okay(found[i],path,base,hashname,hashtype) then + break + end + end end end end end else + local function okayokay(found,path,base,hashname,hashtype) + if find(found,path) then + local full=methodhandler('concatinators',hashtype,hashname,found,base) + if full and full~="" then + result[#result+1]=resolveprefix(full) + return not allresults + end + end + end local hashes=instance.hashes for k=1,#hashes do local hash=hashes[k] - local hashname,hashtype=hash.name,hash.type - if doit(path,files[hashname][base],base,hashname,hashtype,result,allresults) then done=true end - if done and not allresults then break end + local hashname=hash.name + local hashtype=hash.type + if hashname and hashtype then + local found,base=lookup(content,base) + if not found then + elseif type(found)=='string' then + if okay(found,path,base,hashname,hashtype) then + break + end + else + for i=1,#found do + if okay(found[i],path,base,hashname,hashtype) then + break + end + end + end + end end end return result @@ -15095,7 +15291,7 @@ end function resolvers.dowithpath(name,func) local pathlist=resolvers.expandedpathlist(name) for i=1,#pathlist do - func("^"..resolvers.cleanpath(pathlist[i])) + func("^"..cleanpath(pathlist[i])) end end function resolvers.dowithvariable(name,func) @@ -15103,23 +15299,23 @@ function resolvers.dowithvariable(name,func) end function resolvers.locateformat(name) local engine=environment.ownmain or "luatex" - local barename=file.removesuffix(name) - local fullname=file.addsuffix(barename,"fmt") + local barename=removesuffix(name) + local fullname=addsuffix(barename,"fmt") local fmtname=caches.getfirstreadablefile(fullname,"formats",engine) or "" if fmtname=="" then fmtname=resolvers.findfile(fullname) - fmtname=resolvers.cleanpath(fmtname) + fmtname=cleanpath(fmtname) end if fmtname~="" then - local barename=file.removesuffix(fmtname) - local luaname=file.addsuffix(barename,luasuffixes.lua) - local lucname=file.addsuffix(barename,luasuffixes.luc) - local luiname=file.addsuffix(barename,luasuffixes.lui) - if lfs.isfile(luiname) then + local barename=removesuffix(fmtname) + local luaname=addsuffix(barename,luasuffixes.lua) + local lucname=addsuffix(barename,luasuffixes.luc) + local luiname=addsuffix(barename,luasuffixes.lui) + if isfile(luiname) then return barename,luiname - elseif lfs.isfile(lucname) then + elseif isfile(lucname) then return barename,lucname - elseif lfs.isfile(luaname) then + elseif isfile(luaname) then return barename,luaname end end @@ -15141,29 +15337,24 @@ function resolvers.dowithfilesintree(pattern,handle,before,after) local hash=hashes[i] local blobtype=hash.type local blobpath=hash.name - if blobpath then + if blobtype and blobpath then + local total=0 + local checked=0 + local done=0 if before then before(blobtype,blobpath,pattern) end - local files=instance.files[blobpath] - local total,checked,done=0,0,0 - if files then - for k,v in table.sortedhash(files) do - total=total+1 - if find(k,"^remap:") then - elseif find(k,pattern) then - if type(v)=="string" then - checked=checked+1 - if handle(blobtype,blobpath,v,k) then - done=done+1 - end - else - checked=checked+#v - for i=1,#v do - if handle(blobtype,blobpath,v[i],k) then - done=done+1 - end - end + for path,name in filtered(instance.files[blobpath],pattern) do + if type(path)=="string" then + checked=checked+1 + if handle(blobtype,blobpath,path,name) then + done=done+1 + end + else + checked=checked+#path + for i=1,#path do + if handle(blobtype,blobpath,path[i],name) then + done=done+1 end end end @@ -15174,8 +15365,8 @@ function resolvers.dowithfilesintree(pattern,handle,before,after) end end end -resolvers.obsolete=resolvers.obsolete or {} -local obsolete=resolvers.obsolete +local obsolete=resolvers.obsolete or {} +resolvers.obsolete=obsolete resolvers.find_file=resolvers.findfile obsolete.find_file=resolvers.findfile resolvers.find_files=resolvers.findfiles obsolete.find_files=resolvers.findfiles @@ -15186,7 +15377,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-pre"] = package.loaded["data-pre"] or true --- original size: 6643, stripped down to: 4401 +-- original size: 3106, stripped down to: 2563 if not modules then modules={} end modules ['data-pre']={ version=1.001, @@ -15196,44 +15387,51 @@ if not modules then modules={} end modules ['data-pre']={ license="see context related readme files" } local resolvers=resolvers -local prefixes=utilities.storage.allocate() -resolvers.prefixes=prefixes -local cleanpath,findgivenfile,expansion=resolvers.cleanpath,resolvers.findgivenfile,resolvers.expansion +local prefixes=resolvers.prefixes +local cleanpath=resolvers.cleanpath +local findgivenfile=resolvers.findgivenfile +local expansion=resolvers.expansion local getenv=resolvers.getenv -local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match -local joinpath,basename,dirname=file.join,file.basename,file.dirname -local getmetatable,rawset,type=getmetatable,rawset,type +local basename=file.basename +local dirname=file.dirname +local joinpath=file.join +local isfile=lfs.isfile prefixes.environment=function(str) return cleanpath(expansion(str)) end -prefixes.relative=function(str,n) - if io.exists(str) then - elseif io.exists("./"..str) then - str="./"..str - else - local p="../" - for i=1,n or 2 do - if io.exists(p..str) then - str=p..str - break - else - p=p.."../" +local function relative(str,n) + if not isfile(str) then + local pstr="./"..str + if isfile(pstr) then + str=pstr + else + local p="../" + for i=1,n or 2 do + local pstr=p..str + if isfile(pstr) then + str=pstr + break + else + p=p.."../" + end end end end return cleanpath(str) end +local function locate(str) + local fullname=findgivenfile(str) or "" + return cleanpath(fullname~="" and fullname or str) +end +prefixes.relative=relative +prefixes.locate=locate prefixes.auto=function(str) - local fullname=prefixes.relative(str) - if not lfs.isfile(fullname) then - fullname=prefixes.locate(str) + local fullname=relative(str) + if not isfile(fullname) then + fullname=locate(str) end return fullname end -prefixes.locate=function(str) - local fullname=findgivenfile(str) or "" - return cleanpath((fullname~="" and fullname) or str) -end prefixes.filename=function(str) local fullname=findgivenfile(str) or "" return cleanpath(basename((fullname~="" and fullname) or str)) @@ -15277,87 +15475,6 @@ prefixes.kpse=prefixes.locate prefixes.full=prefixes.locate prefixes.file=prefixes.filename prefixes.path=prefixes.pathname -function resolvers.allprefixes(separator) - local all=table.sortedkeys(prefixes) - if separator then - for i=1,#all do - all[i]=all[i]..":" - end - end - return all -end -local function _resolve_(method,target) - local action=prefixes[method] - if action then - return action(target) - else - return method..":"..target - end -end -local resolved,abstract={},{} -function resolvers.resetresolve(str) - resolved,abstract={},{} -end -local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) -local prefix=C(R("az")^2)*P(":") -local target=C((1-S(" \"\';,"))^1) -local notarget=(#S(";,")+P(-1))*Cc("") -local pattern=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) -local function resolve(str) - if type(str)=="table" then - local t={} - for i=1,#str do - t[i]=resolve(str[i]) - end - return t - else - local res=resolved[str] - if not res then - res=lpegmatch(pattern,str) - resolved[str]=res - abstract[res]=str - end - return res - end -end -local function unresolve(str) - return abstract[str] or str -end -resolvers.resolve=resolve -resolvers.unresolve=unresolve -if type(os.uname)=="function" then - for k,v in next,os.uname() do - if not prefixes[k] then - prefixes[k]=function() return v end - end - end -end -if os.type=="unix" then - local pattern - local function makepattern(t,k,v) - if t then - rawset(t,k,v) - end - local colon=P(":") - for k,v in table.sortedpairs(prefixes) do - if p then - p=P(k)+p - else - p=P(k) - end - end - pattern=Cs((p*colon+colon/";"+P(1))^0) - end - makepattern() - getmetatable(prefixes).__newindex=makepattern - function resolvers.repath(str) - return lpegmatch(pattern,str) - end -else - function resolvers.repath(str) - return str - end -end end -- of closure @@ -15419,7 +15536,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-fil"] = package.loaded["data-fil"] or true --- original size: 3801, stripped down to: 3231 +-- original size: 3863, stripped down to: 3310 if not modules then modules={} end modules ['data-fil']={ version=1.001, @@ -15431,30 +15548,31 @@ if not modules then modules={} end modules ['data-fil']={ local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_files=logs.reporter("resolvers","files") local resolvers=resolvers +local resolveprefix=resolvers.resolve local finders,openers,loaders,savers=resolvers.finders,resolvers.openers,resolvers.loaders,resolvers.savers local locators,hashers,generators,concatinators=resolvers.locators,resolvers.hashers,resolvers.generators,resolvers.concatinators local checkgarbage=utilities.garbagecollector and utilities.garbagecollector.check function locators.file(specification) - local name=specification.filename - local realname=resolvers.resolve(name) + local filename=specification.filename + local realname=resolveprefix(filename) if realname and realname~='' and lfs.isdir(realname) then if trace_locating then - report_files("file locator %a found as %a",name,realname) + report_files("file locator %a found as %a",filename,realname) end - resolvers.appendhash('file',name,true) + resolvers.appendhash('file',filename,true) elseif trace_locating then - report_files("file locator %a not found",name) + report_files("file locator %a not found",filename) end end function hashers.file(specification) - local name=specification.filename - local content=caches.loadcontent(name,'files') - resolvers.registerfilehash(name,content,content==nil) + local pathname=specification.filename + local content=caches.loadcontent(pathname,'files') + resolvers.registerfilehash(pathname,content,content==nil) end function generators.file(specification) - local path=specification.filename - local content=resolvers.scanfiles(path,false,true) - resolvers.registerfilehash(path,content,true) + local pathname=specification.filename + local content=resolvers.scanfiles(pathname,false,true) + resolvers.registerfilehash(pathname,content,true) end concatinators.file=file.join function finders.file(specification,filetype) @@ -15736,7 +15854,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-zip"] = package.loaded["data-zip"] or true --- original size: 8489, stripped down to: 6757 +-- original size: 9043, stripped down to: 7073 if not modules then modules={} end modules ['data-zip']={ version=1.001, @@ -15779,7 +15897,7 @@ function zip.openarchive(name) local arch=archives[name] if not arch then local full=resolvers.findfile(name) or "" - arch=(full~="" and zip.open(full)) or false + arch=full~="" and zip.open(full) or false archives[name]=arch end return arch @@ -15938,31 +16056,42 @@ function resolvers.usezipfile(archive) end end function resolvers.registerzipfile(z,tree) - local files,filter={},"" - if tree=="" then - filter="^(.+)/(.-)$" - else - filter=format("^%s/(.+)/(.-)$",tree) - end + local names={} + local files={} + local remap={} + local n=0 + local filter=tree=="" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree) + local register=resolvers.registerfile if trace_locating then report_zip("registering: using filter %a",filter) end - local register,n=resolvers.registerfile,0 for i in z:files() do - local path,name=match(i.filename,filter) - if path then - if name and name~='' then - register(files,name,path) - n=n+1 - else + local filename=i.filename + local path,name=match(filename,filter) + if not path then + n=n+1 + register(names,filename,"") + local usedname=lower(filename) + files[usedname]="" + if usedname~=filename then + remap[usedname]=filename end - else - register(files,i.filename,'') + elseif name and name~="" then n=n+1 + register(names,name,path) + local usedname=lower(name) + files[usedname]=path + if usedname~=name then + remap[usedname]=name + end + else end end report_zip("registering: %s files registered",n) - return files + return { + files=files, + remap=remap, + } end @@ -15972,7 +16101,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tre"] = package.loaded["data-tre"] or true --- original size: 2508, stripped down to: 2074 +-- original size: 4859, stripped down to: 3335 if not modules then modules={} end modules ['data-tre']={ version=1.001, @@ -15981,42 +16110,50 @@ if not modules then modules={} end modules ['data-tre']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local find,gsub,format=string.find,string.gsub,string.format +local find,gsub,lower=string.find,string.gsub,string.lower +local basename,dirname,joinname=file.basename,file.dirname,file .join +local globdir,isdir=dir.glob,lfs.isdir local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_trees=logs.reporter("resolvers","trees") local resolvers=resolvers -local done,found,notfound={},{},resolvers.finders.notfound -function resolvers.finders.tree(specification) +local resolveprefix=resolvers.resolve +local notfound=resolvers.finders.notfound +local collectors={} +local found={} +function resolvers.finders.tree(specification) local spec=specification.filename - local fnd=found[spec] - if fnd==nil then + local okay=found[spec] + if okay==nil then if spec~="" then - local path,name=file.dirname(spec),file.basename(spec) - if path=="" then path="." end - local hash=done[path] - if not hash then - local pattern=path.."/*" - hash=dir.glob(pattern) - done[path]=hash + local path=dirname(spec) + local name=basename(spec) + if path=="" then + path="." + end + local names=collectors[path] + if not names then + local pattern=find(path,"/%*+$") and path or (path.."/*") + names=globdir(pattern) + collectors[path]=names end local pattern="/"..gsub(name,"([%.%-%+])","%%%1").."$" - for k=1,#hash do - local v=hash[k] - if find(v,pattern) then - found[spec]=v - return v + for i=1,#names do + local fullname=names[i] + if find(fullname,pattern) then + found[spec]=fullname + return fullname end end end - fnd=notfound() - found[spec]=fnd + okay=notfound() + found[spec]=okay end - return fnd + return okay end function resolvers.locators.tree(specification) local name=specification.filename - local realname=resolvers.resolve(name) - if realname and realname~='' and lfs.isdir(realname) then + local realname=resolveprefix(name) + if realname and realname~='' and isdir(realname) then if trace_locating then report_trees("locator %a found",realname) end @@ -16033,10 +16170,43 @@ function resolvers.hashers.tree(specification) resolvers.methodhandler("hashers",name) resolvers.generators.file(specification) end -resolvers.concatinators.tree=resolvers.concatinators.file -resolvers.generators.tree=resolvers.generators.file -resolvers.openers.tree=resolvers.openers.file -resolvers.loaders.tree=resolvers.loaders.file +local collectors={} +table.setmetatableindex(collectors,function(t,k) + local rootname=gsub(k,"[/%*]+$","") + local dataname=joinname(rootname,"dirlist") + local data=caches.loadcontent(dataname,"files",dataname) + local content=data and data.content + local lookup=resolvers.get_from_content + if not content then + content=resolvers.scanfiles(rootname) + caches.savecontent(dataname,"files",content,dataname) + end + local files=content.files + local v=function(filename) + local path,name=lookup(content,filename) + if not path then + return filename + elseif type(path)=="table" then + path=path[1] + end + return joinname(rootname,path,name) + end + t[k]=v + return v +end) +function resolvers.finders.dirlist(specification) + local spec=specification.filename + if spec~="" then + local path,name=dirname(spec),basename(spec) + return path and collectors[path](name) or notfound() + end + return notfound() +end +resolvers.locators .dirlist=resolvers.locators .tree +resolvers.hashers .dirlist=resolvers.hashers .tree +resolvers.generators.dirlist=resolvers.generators.file +resolvers.openers .dirlist=resolvers.openers .file +resolvers.loaders .dirlist=resolvers.loaders .file end -- of closure @@ -16221,7 +16391,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-lua"] = package.loaded["data-lua"] or true --- original size: 4237, stripped down to: 3177 +-- original size: 4313, stripped down to: 3227 if not modules then modules={} end modules ['data-lua']={ version=1.001, @@ -16230,7 +16400,7 @@ if not modules then modules={} end modules ['data-lua']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local resolvers,package=resolvers,package +local package,lpeg=package,lpeg local gsub=string.gsub local concat=table.concat local addsuffix=file.addsuffix @@ -16241,9 +16411,11 @@ local luaformats={ 'TEXINPUTS','LUAINPUTS' } local libformats={ 'CLUAINPUTS' } local helpers=package.helpers or {} local methods=helpers.methods or {} +local resolvers=resolvers +local resolveprefix=resolvers.resolve +helpers.report=logs.reporter("resolvers","libraries") trackers.register("resolvers.libraries",function(v) helpers.trace=v end) trackers.register("resolvers.locating",function(v) helpers.trace=v end) -helpers.report=logs.reporter("resolvers","libraries") helpers.sequence={ "already loaded", "preload table", @@ -16258,7 +16430,7 @@ helpers.sequence={ } local pattern=Cs(P("!")^0/""*(P("/")*P(-1)/"/"+P("/")^1/"/"+1)^0) function helpers.cleanpath(path) - return resolvers.resolve(lpegmatch(pattern,path)) + return resolveprefix(lpegmatch(pattern,path)) end local loadedaslib=helpers.loadedaslib local getextraluapaths=package.extraluapaths @@ -16395,7 +16567,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tmf"] = package.loaded["data-tmf"] or true --- original size: 2600, stripped down to: 1627 +-- original size: 2601, stripped down to: 1627 if not modules then modules={} end modules ['data-tmf']={ version=1.001, @@ -16451,7 +16623,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-lst"] = package.loaded["data-lst"] or true --- original size: 2654, stripped down to: 2301 +-- original size: 2734, stripped down to: 2354 if not modules then modules={} end modules ['data-lst']={ version=1.001, @@ -16460,10 +16632,13 @@ if not modules then modules={} end modules ['data-lst']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local find,concat,upper,format=string.find,table.concat,string.upper,string.format +local rawget,type,next=rawget,type,next +local find,concat,upper=string.find,table.concat,string.upper local fastcopy,sortedpairs=table.fastcopy,table.sortedpairs -resolvers.listers=resolvers.listers or {} local resolvers=resolvers +local listers=resolvers.listers or {} +resolvers.listers=listers +local resolveprefix=resolvers.resolve local report_lists=logs.reporter("resolvers","lists") local function tabstr(str) if type(str)=='table' then @@ -16472,7 +16647,7 @@ local function tabstr(str) return str end end -function resolvers.listers.variables(pattern) +function listers.variables(pattern) local instance=resolvers.instance local environment=instance.environment local variables=instance.variables @@ -16493,10 +16668,10 @@ function resolvers.listers.variables(pattern) for key,value in sortedpairs(configured) do if key~="" and (pattern=="" or find(upper(key),pattern)) then report_lists(key) - report_lists(" env: %s",tabstr(rawget(environment,key)) or "unset") - report_lists(" var: %s",tabstr(configured[key]) or "unset") - report_lists(" exp: %s",tabstr(expansions[key]) or "unset") - report_lists(" res: %s",tabstr(resolvers.resolve(expansions[key])) or "unset") + report_lists(" env: %s",tabstr(rawget(environment,key)) or "unset") + report_lists(" var: %s",tabstr(configured[key]) or "unset") + report_lists(" exp: %s",tabstr(expansions[key]) or "unset") + report_lists(" res: %s",tabstr(resolveprefix(expansions[key])) or "unset") end end instance.environment=fastcopy(env) @@ -16504,15 +16679,15 @@ function resolvers.listers.variables(pattern) instance.expansions=fastcopy(exp) end local report_resolved=logs.reporter("system","resolved") -function resolvers.listers.configurations() +function listers.configurations() local configurations=resolvers.instance.specification for i=1,#configurations do - report_resolved("file : %s",resolvers.resolve(configurations[i])) + report_resolved("file : %s",resolveprefix(configurations[i])) end report_resolved("") local list=resolvers.expandedpathfromlist(resolvers.splitpath(resolvers.luacnfspec)) for i=1,#list do - local li=resolvers.resolve(list[i]) + local li=resolveprefix(list[i]) if lfs.isdir(li) then report_resolved("path - %s",li) else @@ -16951,8 +17126,8 @@ end -- of closure -- used libraries : l-lua.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-sto.lua util-prs.lua util-fmt.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-mrg.lua util-tpl.lua util-env.lua luat-env.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua util-lib.lua luat-sta.lua luat-fmt.lua -- skipped libraries : - --- original bytes : 699655 --- stripped bytes : 249540 +-- original bytes : 704727 +-- stripped bytes : 250243 -- end library merge diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv index 53a57ef9c..0c5dbb485 100644 --- a/tex/context/base/cont-new.mkiv +++ b/tex/context/base/cont-new.mkiv @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2014.06.27 10:53} +\newcontextversion{2014.07.03 14:52} %D This file is loaded at runtime, thereby providing an excellent place for %D hacks, patches, extensions and new features. diff --git a/tex/context/base/context-version.pdf b/tex/context/base/context-version.pdf Binary files differindex 303d0d600..b95c4f339 100644 --- a/tex/context/base/context-version.pdf +++ b/tex/context/base/context-version.pdf diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv index b936c288d..de7086acb 100644 --- a/tex/context/base/context.mkiv +++ b/tex/context/base/context.mkiv @@ -28,7 +28,7 @@ %D up and the dependencies are more consistent. \edef\contextformat {\jobname} -\edef\contextversion{2014.06.27 10:53} +\edef\contextversion{2014.07.03 14:52} \edef\contextkind {beta} %D For those who want to use this: diff --git a/tex/context/base/core-env.mkiv b/tex/context/base/core-env.mkiv index 9207d9f4a..30fc83b4b 100644 --- a/tex/context/base/core-env.mkiv +++ b/tex/context/base/core-env.mkiv @@ -390,6 +390,8 @@ % but it won't work out well with multiple setups (intercepted at the % lua end) that then get only one argument. +\def\fastsetup#1{\csname\??setup:#1\endcsname\empty} % no checking and we assume it being defined (at least for now) + % the next one is meant for \c!setups situations, hence the check for % a shortcut diff --git a/tex/context/base/data-exp.lua b/tex/context/base/data-exp.lua index 9534e73a0..6edaa8c6a 100644 --- a/tex/context/base/data-exp.lua +++ b/tex/context/base/data-exp.lua @@ -13,14 +13,17 @@ local Ct, Cs, Cc, Carg, P, C, S = lpeg.Ct, lpeg.Cs, lpeg.Cc, lpeg.Carg, lpeg.P, local type, next = type, next local ostype = os.type -local collapsepath = file.collapsepath +local collapsepath, joinpath, basename = file.collapsepath, file.join, file.basename local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end) local trace_expansions = false trackers.register("resolvers.expansions", function(v) trace_expansions = v end) +local trace_globbing = true trackers.register("resolvers.globbing", function(v) trace_globbing = v end) local report_expansions = logs.reporter("resolvers","expansions") +local report_globbing = logs.reporter("resolvers","globbing") -local resolvers = resolvers +local resolvers = resolvers +local resolveprefix = resolvers.resolve -- As this bit of code is somewhat special it gets its own module. After -- all, when working on the main resolver code, I don't want to scroll @@ -177,34 +180,28 @@ end -- {a,b,c/{p,q/{x,y,z},w}v,d/{p,q,r}} -- {$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c} -local cleanup = lpeg.replacer { - { "!" , "" }, - { "\\" , "/" }, -} +local usedhomedir = nil +local donegation = (P("!") /"" )^0 +local doslashes = (P("\\")/"/" + 1)^0 -function resolvers.cleanpath(str) -- tricky, maybe only simple paths - local doslashes = (P("\\")/"/" + 1)^0 - local donegation = (P("!") /"" )^0 - local homedir = lpegmatch(Cs(donegation * doslashes),environment.homedir or "") - if homedir == "~" or homedir == "" or not lfs.isdir(homedir) then - if trace_expansions then - report_expansions("no home dir set, ignoring dependent paths") - end - function resolvers.cleanpath(str) - if not str or find(str,"~",1,true) then - return "" -- special case - else - return lpegmatch(cleanup,str) +local function expandedhome() + if not usedhomedir then + usedhomedir = lpegmatch(Cs(donegation * doslashes),environment.homedir or "") + if usedhomedir == "~" or usedhomedir == "" or not lfs.isdir(usedhomedir) then + if trace_expansions then + report_expansions("no home dir set, ignoring dependent path using current path") end - end - else - local dohome = ((P("~")+P("$HOME"))/homedir)^0 - local cleanup = Cs(donegation * dohome * doslashes) - function resolvers.cleanpath(str) - return str and lpegmatch(cleanup,str) or "" + usedhomedir = "." end end - return resolvers.cleanpath(str) + return usedhomedir +end + +local dohome = ((P("~")+P("$HOME")+P("%HOME%"))/expandedhome)^0 +local cleanup = Cs(donegation * dohome * doslashes) + +resolvers.cleanpath = function(str) + return str and lpegmatch(cleanup,str) or "" end -- print(resolvers.cleanpath("")) @@ -216,11 +213,18 @@ end -- This one strips quotes and funny tokens. -local expandhome = P("~") / "$HOME" -- environment.homedir or "home:" +-- we have several options here: +-- +-- expandhome = P("~") / "$HOME" : relocateble +-- expandhome = P("~") / "home:" : relocateble +-- expandhome = P("~") / environment.homedir : frozen but unexpanded +-- expandhome = P("~") = dohome : frozen and expanded + +local expandhome = P("~") / "$HOME" -local dodouble = P('"')/"" * (expandhome + (1 - P('"')))^0 * P('"')/"" -local dosingle = P("'")/"" * (expandhome + (1 - P("'")))^0 * P("'")/"" -local dostring = (expandhome + 1 )^0 +local dodouble = P('"') / "" * (expandhome + (1 - P('"')))^0 * P('"') / "" +local dosingle = P("'") / "" * (expandhome + (1 - P("'")))^0 * P("'") / "" +local dostring = (expandhome + 1 )^0 local stripper = Cs( lpegpatterns.unspacer * (dosingle + dodouble + dostring) * lpegpatterns.unspacer @@ -285,7 +289,7 @@ end function resolvers.joinpath(str) if type(str) == 'table' then - return file.joinpath(str) + return joinpath(str) else return str end @@ -293,25 +297,25 @@ end -- The next function scans directories and returns a hash where the -- entries are either strings or tables. - +-- -- starting with . or .. etc or funny char - ---~ local l_forbidden = S("~`!#$%^&*()={}[]:;\"\'||\\/<>,?\n\r\t") ---~ local l_confusing = P(" ") ---~ local l_character = lpegpatterns.utf8 ---~ local l_dangerous = P(".") - ---~ local l_normal = (l_character - l_forbidden - l_confusing - l_dangerous) * (l_character - l_forbidden - l_confusing^2)^0 * P(-1) ---~ ----- l_normal = l_normal * Cc(true) + Cc(false) - ---~ local function test(str) ---~ print(str,lpegmatch(l_normal,str)) ---~ end ---~ test("ヒラギノ明朝 Pro W3") ---~ test("..ヒラギノ明朝 Pro W3") ---~ test(":ヒラギノ明朝 Pro W3;") ---~ test("ヒラギノ明朝 /Pro W3;") ---~ test("ヒラギノ明朝 Pro W3") +-- +-- local l_forbidden = S("~`!#$%^&*()={}[]:;\"\'||\\/<>,?\n\r\t") +-- local l_confusing = P(" ") +-- local l_character = lpegpatterns.utf8 +-- local l_dangerous = P(".") +-- +-- local l_normal = (l_character - l_forbidden - l_confusing - l_dangerous) * (l_character - l_forbidden - l_confusing^2)^0 * P(-1) +-- ----- l_normal = l_normal * Cc(true) + Cc(false) +-- +-- local function test(str) +-- print(str,lpegmatch(l_normal,str)) +-- end +-- test("ヒラギノ明朝 Pro W3") +-- test("..ヒラギノ明朝 Pro W3") +-- test(":ヒラギノ明朝 Pro W3;") +-- test("ヒラギノ明朝 /Pro W3;") +-- test("ヒラギノ明朝 Pro W3") -- a lot of this caching can be stripped away when we have ssd's everywhere -- @@ -319,41 +323,65 @@ end local attributes, directory = lfs.attributes, lfs.dir -local weird = P(".")^1 + lpeg.anywhere(S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t")) -local timer = { } -local scanned = { } -local nofscans = 0 -local scancache = { } +local weird = P(".")^1 + lpeg.anywhere(S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t")) +local timer = { } +local scanned = { } +local nofscans = 0 +local scancache = { } +local fullcache = { } +----- simplecache = { } +local nofsharedscans = 0 + +-- So, we assume either a lowercase name or a mixed case one but only one such case +-- as having Foo fOo foo FoO FOo etc on the system is braindead in any sane project. -local function scan(files,spec,path,n,m,r) - local full = (path == "" and spec) or (spec .. path .. '/') +local function scan(files,remap,spec,path,n,m,r,onlyone) + local full = path == "" and spec or (spec .. path .. '/') local dirs = { } local nofdirs = 0 for name in directory(full) do if not lpegmatch(weird,name) then - local mode = attributes(full..name,'mode') - if mode == 'file' then + local mode = attributes(full..name,"mode") + if mode == "file" then n = n + 1 - local f = files[name] - if f then - if type(f) == 'string' then - files[name] = { f, path } + local lower = lower(name) + local paths = files[lower] + if paths then + if onlyone then + -- forget about it else - f[#f+1] = path + if type(paths) == "string" then + files[lower] = { paths, path } + else + paths[#paths+1] = path + end + if name ~= lower then + local rl = remap[lower] + if not rl then + remap[lower] = name + r = r + 1 + elseif trace_globbing and rl ~= name then + report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) + end + end end else -- probably unique anyway - files[name] = path - local lower = lower(name) + files[lower] = path if name ~= lower then - files["remap:"..lower] = name - r = r + 1 + local rl = remap[lower] + if not rl then + remap[lower] = name + r = r + 1 + elseif trace_globbing and rl ~= name then + report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) + end end end - elseif mode == 'directory' then + elseif mode == "directory" then m = m + 1 nofdirs = nofdirs + 1 if path ~= "" then - dirs[nofdirs] = path..'/'..name + dirs[nofdirs] = path .. "/" .. name else dirs[nofdirs] = name end @@ -363,113 +391,55 @@ local function scan(files,spec,path,n,m,r) if nofdirs > 0 then sort(dirs) for i=1,nofdirs do - files, n, m, r = scan(files,spec,dirs[i],n,m,r) + files, remap, n, m, r = scan(files,remap,spec,dirs[i],n,m,r,onlyone) end end scancache[sub(full,1,-2)] = files - return files, n, m, r + return files, remap, n, m, r end -local fullcache = { } - -function resolvers.scanfiles(path,branch,usecache) - statistics.starttiming(timer) - local realpath = resolvers.resolve(path) -- no shortcut +function resolvers.scanfiles(path,branch,usecache,onlyonce) + local realpath = resolveprefix(path) if usecache then - local files = fullcache[realpath] - if files then + local content = fullcache[realpath] + if content then if trace_locating then - report_expansions("using caches scan of path %a, branch %a",path,branch or path) + report_expansions("using cached scan of path %a, branch %a",path,branch or path) end - return files + nofsharedscans = nofsharedscans + 1 + return content end end + -- + statistics.starttiming(timer) if trace_locating then report_expansions("scanning path %a, branch %a",path,branch or path) end - local files, n, m, r = scan({ },realpath .. '/',"",0,0,0) - files.__path__ = path -- can be selfautoparent:texmf-whatever - files.__files__ = n - files.__directories__ = m - files.__remappings__ = r + local files, remap, n, m, r = scan({ },{ },realpath .. '/',"",0,0,0,onlyonce) + local content = { + metadata = { + path = path, -- can be selfautoparent:texmf-whatever + files = n, + directories = m, + remappings = r, + }, + files = files, + remap = remap, + } if trace_locating then report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r) end if usecache then scanned[#scanned+1] = realpath - fullcache[realpath] = files + fullcache[realpath] = content end nofscans = nofscans + 1 statistics.stoptiming(timer) - return files -end - -local function simplescan(files,spec,path) -- first match only, no map and such - local full = (path == "" and spec) or (spec .. path .. '/') - local dirs = { } - local nofdirs = 0 - for name in directory(full) do - if not lpegmatch(weird,name) then - local mode = attributes(full..name,'mode') - if mode == 'file' then - if not files[name] then - -- only first match - files[name] = path - end - elseif mode == 'directory' then - nofdirs = nofdirs + 1 - if path ~= "" then - dirs[nofdirs] = path..'/'..name - else - dirs[nofdirs] = name - end - end - end - end - if nofdirs > 0 then - sort(dirs) - for i=1,nofdirs do - files = simplescan(files,spec,dirs[i]) - end - end - return files + return content end -local simplecache = { } -local nofsharedscans = 0 - function resolvers.simplescanfiles(path,branch,usecache) - statistics.starttiming(timer) - local realpath = resolvers.resolve(path) -- no shortcut - if usecache then - local files = simplecache[realpath] - if not files then - files = scancache[realpath] - if files then - nofsharedscans = nofsharedscans + 1 - end - end - if files then - if trace_locating then - report_expansions("using caches scan of path %a, branch %a",path,branch or path) - end - return files - end - end - if trace_locating then - report_expansions("scanning path %a, branch %a",path,branch or path) - end - local files = simplescan({ },realpath .. '/',"") - if trace_locating then - report_expansions("%s files found",table.count(files)) - end - if usecache then - scanned[#scanned+1] = realpath - simplecache[realpath] = files - end - nofscans = nofscans + 1 - statistics.stoptiming(timer) - return files + return resolvers.scanfiles(path,branch,usecache,true) -- onlyonce end function resolvers.scandata() @@ -482,4 +452,54 @@ function resolvers.scandata() } end ---~ print(table.serialize(resolvers.scanfiles("t:/sources"))) +function resolvers.get_from_content(content,path,name) -- or (content,name) + local files = content.files + if not files then + return + end + local remap = content.remap + if not remap then + return + end + if name then + -- this one resolves a remapped name + local used = lower(name) + return path, remap[used] or used + else + -- this one does a lookup and resolves a remapped name + local name = path + local used = lower(name) + local path = files[used] + if path then + return path, remap[used] or used + end + end +end + +local nothing = function() end + +function resolvers.filtered_from_content(content,pattern) + if content and type(pattern) == "string" then + local pattern = lower(pattern) + local files = content.files + local remap = content.remap + if files and remap then + local n = next(files) + local function iterator() + while n do + local k = n + n = next(files,k) + if find(k,pattern) then + return files[k], remap and remap[k] or k + end + end + end + return iterator + end + end + return nothing +end + + +-- inspect(resolvers.simplescanfiles("e:/temporary/mb-mp")) +-- inspect(resolvers.scanfiles("e:/temporary/mb-mp")) diff --git a/tex/context/base/data-fil.lua b/tex/context/base/data-fil.lua index 09129e03c..b699fc9e3 100644 --- a/tex/context/base/data-fil.lua +++ b/tex/context/base/data-fil.lua @@ -10,7 +10,8 @@ local trace_locating = false trackers.register("resolvers.locating", function(v local report_files = logs.reporter("resolvers","files") -local resolvers = resolvers +local resolvers = resolvers +local resolveprefix = resolvers.resolve local finders, openers, loaders, savers = resolvers.finders, resolvers.openers, resolvers.loaders, resolvers.savers local locators, hashers, generators, concatinators = resolvers.locators, resolvers.hashers, resolvers.generators, resolvers.concatinators @@ -18,35 +19,34 @@ local locators, hashers, generators, concatinators = resolvers.locators, resolve local checkgarbage = utilities.garbagecollector and utilities.garbagecollector.check function locators.file(specification) - local name = specification.filename - local realname = resolvers.resolve(name) -- no shortcut + local filename = specification.filename + local realname = resolveprefix(filename) -- no shortcut if realname and realname ~= '' and lfs.isdir(realname) then if trace_locating then - report_files("file locator %a found as %a",name,realname) + report_files("file locator %a found as %a",filename,realname) end - resolvers.appendhash('file',name,true) -- cache + resolvers.appendhash('file',filename,true) -- cache elseif trace_locating then - report_files("file locator %a not found",name) + report_files("file locator %a not found",filename) end end function hashers.file(specification) - local name = specification.filename - local content = caches.loadcontent(name,'files') - resolvers.registerfilehash(name,content,content==nil) + local pathname = specification.filename + local content = caches.loadcontent(pathname,'files') + resolvers.registerfilehash(pathname,content,content==nil) end function generators.file(specification) - local path = specification.filename - local content = resolvers.scanfiles(path,false,true) -- scan once ---~ inspect(content) - resolvers.registerfilehash(path,content,true) + local pathname = specification.filename + local content = resolvers.scanfiles(pathname,false,true) -- scan once + resolvers.registerfilehash(pathname,content,true) end concatinators.file = file.join function finders.file(specification,filetype) - local filename = specification.filename + local filename = specification.filename local foundname = resolvers.findfile(filename,filetype) if foundname and foundname ~= "" then if trace_locating then diff --git a/tex/context/base/data-ini.lua b/tex/context/base/data-ini.lua index bbd233ae7..ab5668c0b 100644 --- a/tex/context/base/data-ini.lua +++ b/tex/context/base/data-ini.lua @@ -6,10 +6,12 @@ if not modules then modules = { } end modules ['data-ini'] = { license = "see context related readme files", } +local next, type, getmetatable, rawset = next, type, getmetatable, rawset local gsub, find, gmatch, char = string.gsub, string.find, string.gmatch, string.char -local next, type = next, type - local filedirname, filebasename, filejoin = file.dirname, file.basename, file.join +local ostype, osname, osuname, ossetenv, osgetenv = os.type, os.name, os.uname, os.setenv, os.getenv + +local P, S, R, C, Cs, Cc, lpegmatch = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.match local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end) local trace_detail = false trackers.register("resolvers.details", function(v) trace_detail = v end) @@ -17,11 +19,9 @@ local trace_expansions = false trackers.register("resolvers.expansions", functi local report_initialization = logs.reporter("resolvers","initialization") -local ostype, osname, ossetenv, osgetenv = os.type, os.name, os.setenv, os.getenv - --- The code here used to be part of a data-res but for convenience --- we now split it over multiple files. As this file is now the --- starting point we introduce resolvers here. +-- The code here used to be part of a data-res but for convenience we now split it over multiple +-- files. As this file is now the starting point we introduce resolvers here. We also put some +-- helpers here that later can be reimplemented of extended. resolvers = resolvers or { } local resolvers = resolvers @@ -225,8 +225,117 @@ end -- a forward definition -if not resolvers.resolve then - function resolvers.resolve (s) return s end - function resolvers.unresolve(s) return s end - function resolvers.repath (s) return s end +-- Because we use resolvers.resolve a lot later on, we will implement the basics here and +-- add more later. + +local prefixes = utilities.storage.allocate() +resolvers.prefixes = prefixes + +local resolved = { } +local abstract = { } + +function resolvers.resetresolve(str) + resolved, abstract = { }, { } +end + +function resolvers.allprefixes(separator) + local all = table.sortedkeys(prefixes) + if separator then + for i=1,#all do + all[i] = all[i] .. ":" + end + end + return all +end + +local function _resolve_(method,target) + local action = prefixes[method] + if action then + return action(target) + else + return method .. ":" .. target + end +end + +function resolvers.unresolve(str) + return abstract[str] or str +end + +-- home:xx;selfautoparent:xx; + +local pattern = Cs((C(R("az")^2) * P(":") * C((1-S(" \"\';,"))^1) / _resolve_ + P(1))^0) + +local prefix = C(R("az")^2) * P(":") +local target = C((1-S(" \"\';,"))^1) +local notarget = (#S(";,") + P(-1)) * Cc("") + +local pattern = Cs(((prefix * (target + notarget)) / _resolve_ + P(1))^0) + +local function resolve(str) -- use schemes, this one is then for the commandline only + if type(str) == "table" then + local res = { } + for i=1,#str do + res[i] = resolve(str[i]) + end + return res + else + local res = resolved[str] + if not res then + res = lpegmatch(pattern,str) + resolved[str] = res + abstract[res] = str + end + return res + end +end + +resolvers.resolve = resolve + +if type(osuname) == "function" then + + for k, v in next, osuname() do + if not prefixes[k] then + prefixes[k] = function() return v end + end + end + +end + +if ostype == "unix" then + + -- We need to distringuish between a prefix and something else : so we + -- have a special repath variant for linux. Also, when a new prefix is + -- defined, we need to remake the matcher. + + local pattern + + local function makepattern(t,k,v) + if t then + rawset(t,k,v) + end + local colon = P(":") + for k, v in table.sortedpairs(prefixes) do + if p then + p = P(k) + p + else + p = P(k) + end + end + pattern = Cs((p * colon + colon/";" + P(1))^0) + end + + makepattern() + + table.setmetatablenewindex(prefixes,makepattern) + + function resolvers.repath(str) + return lpegmatch(pattern,str) + end + +else -- already the default: + + function resolvers.repath(str) + return str + end + end diff --git a/tex/context/base/data-lst.lua b/tex/context/base/data-lst.lua index 8996fa251..e4621a6e1 100644 --- a/tex/context/base/data-lst.lua +++ b/tex/context/base/data-lst.lua @@ -8,12 +8,16 @@ if not modules then modules = { } end modules ['data-lst'] = { -- used in mtxrun, can be loaded later .. todo -local find, concat, upper, format = string.find, table.concat, string.upper, string.format +local rawget, type, next = rawget, type, next + +local find, concat, upper = string.find, table.concat, string.upper local fastcopy, sortedpairs = table.fastcopy, table.sortedpairs -resolvers.listers = resolvers.listers or { } +local resolvers = resolvers +local listers = resolvers.listers or { } +resolvers.listers = listers -local resolvers = resolvers +local resolveprefix = resolvers.resolve local report_lists = logs.reporter("resolvers","lists") @@ -25,7 +29,7 @@ local function tabstr(str) end end -function resolvers.listers.variables(pattern) +function listers.variables(pattern) local instance = resolvers.instance local environment = instance.environment local variables = instance.variables @@ -46,10 +50,10 @@ function resolvers.listers.variables(pattern) for key, value in sortedpairs(configured) do if key ~= "" and (pattern == "" or find(upper(key),pattern)) then report_lists(key) - report_lists(" env: %s",tabstr(rawget(environment,key)) or "unset") - report_lists(" var: %s",tabstr(configured[key]) or "unset") - report_lists(" exp: %s",tabstr(expansions[key]) or "unset") - report_lists(" res: %s",tabstr(resolvers.resolve(expansions[key])) or "unset") + report_lists(" env: %s",tabstr(rawget(environment,key)) or "unset") + report_lists(" var: %s",tabstr(configured[key]) or "unset") + report_lists(" exp: %s",tabstr(expansions[key]) or "unset") + report_lists(" res: %s",tabstr(resolveprefix(expansions[key])) or "unset") end end instance.environment = fastcopy(env) @@ -59,15 +63,15 @@ end local report_resolved = logs.reporter("system","resolved") -function resolvers.listers.configurations() +function listers.configurations() local configurations = resolvers.instance.specification for i=1,#configurations do - report_resolved("file : %s",resolvers.resolve(configurations[i])) + report_resolved("file : %s",resolveprefix(configurations[i])) end report_resolved("") local list = resolvers.expandedpathfromlist(resolvers.splitpath(resolvers.luacnfspec)) for i=1,#list do - local li = resolvers.resolve(list[i]) + local li = resolveprefix(list[i]) if lfs.isdir(li) then report_resolved("path - %s",li) else diff --git a/tex/context/base/data-lua.lua b/tex/context/base/data-lua.lua index 0e7c81181..7c12a5940 100644 --- a/tex/context/base/data-lua.lua +++ b/tex/context/base/data-lua.lua @@ -8,7 +8,7 @@ if not modules then modules = { } end modules ['data-lua'] = { -- This is now a plug in into l-lua (as we also use the extra paths elsewhere). -local resolvers, package = resolvers, package +local package, lpeg = package, lpeg local gsub = string.gsub local concat = table.concat @@ -16,18 +16,21 @@ local addsuffix = file.addsuffix local P, S, Cs, lpegmatch = lpeg.P, lpeg.S, lpeg.Cs, lpeg.match -local luasuffixes = { 'tex', 'lua' } -local libsuffixes = { 'lib' } -local luaformats = { 'TEXINPUTS', 'LUAINPUTS' } -local libformats = { 'CLUAINPUTS' } -local helpers = package.helpers or { } -local methods = helpers.methods or { } +local luasuffixes = { 'tex', 'lua' } +local libsuffixes = { 'lib' } +local luaformats = { 'TEXINPUTS', 'LUAINPUTS' } +local libformats = { 'CLUAINPUTS' } +local helpers = package.helpers or { } +local methods = helpers.methods or { } + +local resolvers = resolvers +local resolveprefix = resolvers.resolve + +helpers.report = logs.reporter("resolvers","libraries") trackers.register("resolvers.libraries", function(v) helpers.trace = v end) trackers.register("resolvers.locating", function(v) helpers.trace = v end) -helpers.report = logs.reporter("resolvers","libraries") - helpers.sequence = { "already loaded", "preload table", @@ -44,7 +47,7 @@ helpers.sequence = { local pattern = Cs(P("!")^0 / "" * (P("/") * P(-1) / "/" + P("/")^1 / "/" + 1)^0) function helpers.cleanpath(path) -- hm, don't we have a helper for this? - return resolvers.resolve(lpegmatch(pattern,path)) + return resolveprefix(lpegmatch(pattern,path)) end local loadedaslib = helpers.loadedaslib diff --git a/tex/context/base/data-met.lua b/tex/context/base/data-met.lua index 67b9eb22b..4e8a48f50 100644 --- a/tex/context/base/data-met.lua +++ b/tex/context/base/data-met.lua @@ -36,8 +36,6 @@ local function splitmethod(filename) -- todo: filetype in specification end filename = file.collapsepath(filename,".") -- hm, we should keep ./ in some cases - -- filename = gsub(filename,"^%./",getcurrentdir().."/") -- we will merge dir.expandname and collapse some day - if not find(filename,"://",1,true) then return { scheme = "file", path = filename, original = filename, filename = filename } end diff --git a/tex/context/base/data-pre.lua b/tex/context/base/data-pre.lua index f2f5bddc4..edfe53dab 100644 --- a/tex/context/base/data-pre.lua +++ b/tex/context/base/data-pre.lua @@ -6,63 +6,61 @@ if not modules then modules = { } end modules ['data-pre'] = { license = "see context related readme files" } --- It could be interesting to hook the resolver in the file --- opener so that unresolved prefixes travel around and we --- get more abstraction. +local resolvers = resolvers +local prefixes = resolvers.prefixes --- As we use this beforehand we will move this up in the chain --- of loading. +local cleanpath = resolvers.cleanpath +local findgivenfile = resolvers.findgivenfile +local expansion = resolvers.expansion +local getenv = resolvers.getenv -- we can probably also use resolvers.expansion ---~ print(resolvers.resolve("abc env:tmp file:cont-en.tex path:cont-en.tex full:cont-en.tex rel:zapf/one/p-chars.tex")) +local basename = file.basename +local dirname = file.dirname +local joinpath = file.join -local resolvers = resolvers -local prefixes = utilities.storage.allocate() -resolvers.prefixes = prefixes - -local cleanpath, findgivenfile, expansion = resolvers.cleanpath, resolvers.findgivenfile, resolvers.expansion -local getenv = resolvers.getenv -- we can probably also use resolvers.expansion -local P, S, R, C, Cs, Cc, lpegmatch = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.match -local joinpath, basename, dirname = file.join, file.basename, file.dirname -local getmetatable, rawset, type = getmetatable, rawset, type - --- getenv = function(...) return resolvers.getenv(...) end -- needs checking (definitions changes later on) +local isfile = lfs.isfile prefixes.environment = function(str) return cleanpath(expansion(str)) end -prefixes.relative = function(str,n) -- lfs.isfile - if io.exists(str) then - -- nothing - elseif io.exists("./" .. str) then - str = "./" .. str - else - local p = "../" - for i=1,n or 2 do - if io.exists(p .. str) then - str = p .. str - break - else - p = p .. "../" +local function relative(str,n) + if not isfile(str) then + local pstr = "./" .. str + if isfile(pstr) then + str = pstr + else + local p = "../" + for i=1,n or 2 do + local pstr = p .. str + if isfile(pstr) then + str = pstr + break + else + p = p .. "../" + end end end end return cleanpath(str) end +local function locate(str) + local fullname = findgivenfile(str) or "" + return cleanpath(fullname ~= "" and fullname or str) +end + +prefixes.relative = relative +prefixes.locate = locate + prefixes.auto = function(str) - local fullname = prefixes.relative(str) - if not lfs.isfile(fullname) then - fullname = prefixes.locate(str) + local fullname = relative(str) + if not isfile(fullname) then + fullname = locate(str) end return fullname end -prefixes.locate = function(str) - local fullname = findgivenfile(str) or "" - return cleanpath((fullname ~= "" and fullname) or str) -end - prefixes.filename = function(str) local fullname = findgivenfile(str) or "" return cleanpath(basename((fullname ~= "" and fullname) or str)) -- no cleanpath needed here @@ -115,132 +113,3 @@ prefixes.kpse = prefixes.locate prefixes.full = prefixes.locate prefixes.file = prefixes.filename prefixes.path = prefixes.pathname - -function resolvers.allprefixes(separator) - local all = table.sortedkeys(prefixes) - if separator then - for i=1,#all do - all[i] = all[i] .. ":" - end - end - return all -end - -local function _resolve_(method,target) - local action = prefixes[method] - if action then - return action(target) - else - return method .. ":" .. target - end -end - -local resolved, abstract = { }, { } - -function resolvers.resetresolve(str) - resolved, abstract = { }, { } -end - --- todo: use an lpeg (see data-lua for !! / stripper) - --- local function resolve(str) -- use schemes, this one is then for the commandline only --- if type(str) == "table" then --- local t = { } --- for i=1,#str do --- t[i] = resolve(str[i]) --- end --- return t --- else --- local res = resolved[str] --- if not res then --- res = gsub(str,"([a-z][a-z]+):([^ \"\';,]*)",_resolve_) -- home:xx;selfautoparent:xx; etc (comma added) --- resolved[str] = res --- abstract[res] = str --- end --- return res --- end --- end - --- home:xx;selfautoparent:xx; - -local pattern = Cs((C(R("az")^2) * P(":") * C((1-S(" \"\';,"))^1) / _resolve_ + P(1))^0) - -local prefix = C(R("az")^2) * P(":") -local target = C((1-S(" \"\';,"))^1) -local notarget = (#S(";,") + P(-1)) * Cc("") - -local pattern = Cs(((prefix * (target + notarget)) / _resolve_ + P(1))^0) - -local function resolve(str) -- use schemes, this one is then for the commandline only - if type(str) == "table" then - local t = { } - for i=1,#str do - t[i] = resolve(str[i]) - end - return t - else - local res = resolved[str] - if not res then - res = lpegmatch(pattern,str) - resolved[str] = res - abstract[res] = str - end - return res - end -end - -local function unresolve(str) - return abstract[str] or str -end - -resolvers.resolve = resolve -resolvers.unresolve = unresolve - -if type(os.uname) == "function" then - - for k, v in next, os.uname() do - if not prefixes[k] then - prefixes[k] = function() return v end - end - end - -end - -if os.type == "unix" then - - -- We need to distringuish between a prefix and something else : so we - -- have a special repath variant for linux. Also, when a new prefix is - -- defined, we need to remake the matcher. - - local pattern - - local function makepattern(t,k,v) - if t then - rawset(t,k,v) - end - local colon = P(":") - for k, v in table.sortedpairs(prefixes) do - if p then - p = P(k) + p - else - p = P(k) - end - end - pattern = Cs((p * colon + colon/";" + P(1))^0) - end - - makepattern() - - getmetatable(prefixes).__newindex = makepattern - - function resolvers.repath(str) - return lpegmatch(pattern,str) - end - -else -- already the default: - - function resolvers.repath(str) - return str - end - -end diff --git a/tex/context/base/data-res.lua b/tex/context/base/data-res.lua index d79d78a72..844a0601f 100644 --- a/tex/context/base/data-res.lua +++ b/tex/context/base/data-res.lua @@ -18,7 +18,7 @@ if not modules then modules = { } end modules ['data-res'] = { -- todo: cache:/// home:/// selfautoparent:/// (sometime end 2012) local gsub, find, lower, upper, match, gmatch = string.gsub, string.find, string.lower, string.upper, string.match, string.gmatch -local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys +local concat, insert, sortedkeys, sortedhash = table.concat, table.insert, table.sortedkeys, table.sortedhash local next, type, rawget = next, type, rawget local os = os @@ -29,14 +29,22 @@ local formatters = string.formatters local filedirname = file.dirname local filebasename = file.basename local suffixonly = file.suffixonly +local addsuffix = file.addsuffix +local removesuffix = file.removesuffix local filejoin = file.join local collapsepath = file.collapsepath local joinpath = file.joinpath +local is_qualified_path = file.is_qualified_path + local allocate = utilities.storage.allocate local settings_to_array = utilities.parsers.settings_to_array + +local getcurrentdir = lfs.currentdir +local isfile = lfs.isfile +local isdir = lfs.isdir + local setmetatableindex = table.setmetatableindex local luasuffixes = utilities.lua.suffixes -local getcurrentdir = lfs.currentdir local trace_locating = false trackers .register("resolvers.locating", function(v) trace_locating = v end) local trace_detail = false trackers .register("resolvers.details", function(v) trace_detail = v end) @@ -45,19 +53,23 @@ local resolve_otherwise = true directives.register("resolvers.otherwise", fun local report_resolving = logs.reporter("resolvers","resolving") -local resolvers = resolvers +local resolvers = resolvers local expandedpathfromlist = resolvers.expandedpathfromlist local checkedvariable = resolvers.checkedvariable local splitconfigurationpath = resolvers.splitconfigurationpath local methodhandler = resolvers.methodhandler +local filtered = resolvers.filtered_from_content +local lookup = resolvers.get_from_content +local cleanpath = resolvers.cleanpath +local resolveprefix = resolvers.resolve -local initializesetter = utilities.setters.initialize +local initializesetter = utilities.setters.initialize local ostype, osname, osenv, ossetenv, osgetenv = os.type, os.name, os.env, os.setenv, os.getenv -resolvers.cacheversion = '1.0.1' -resolvers.configbanner = '' +resolvers.cacheversion = "1.100" +resolvers.configbanner = "" resolvers.homedir = environment.homedir resolvers.criticalvars = allocate { "SELFAUTOLOC", "SELFAUTODIR", "SELFAUTOPARENT", "TEXMFCNF", "TEXMF", "TEXOS" } resolvers.luacnfname = "texmfcnf.lua" @@ -155,7 +167,7 @@ function resolvers.setenv(key,value,raw) -- we feed back into the environment, and as this is used -- by other applications (via os.execute) we need to make -- sure that prefixes are resolve - ossetenv(key,raw and value or resolvers.resolve(value)) + ossetenv(key,raw and value or resolveprefix(value)) end end @@ -178,7 +190,7 @@ resolvers.env = getenv -- We are going to use some metatable trickery where we backtrack from -- expansion to variable to environment. -local function resolve(k) +local function resolvevariable(k) return instance.expansions[k] end @@ -191,12 +203,12 @@ local somekey = C(R("az","AZ","09","__","--")^1) local somethingelse = P(";") * ((1-S("!{}/\\"))^1 * P(";") / "") + P(";") * (P(";") / "") + P(1) -local variableexpander = Cs( (somevariable * (somekey/resolve) + somethingelse)^1 ) +local variableexpander = Cs( (somevariable * (somekey/resolvevariable) + somethingelse)^1 ) local cleaner = P("\\") / "/" + P(";") * S("!{}/\\")^0 * P(";")^1 / ";" local variablecleaner = Cs((cleaner + P(1))^0) -local somevariable = R("az","AZ","09","__","--")^1 / resolve +local somevariable = R("az","AZ","09","__","--")^1 / resolvevariable local variable = (P("$")/"") * (somevariable + (P("{")/"") * somevariable * (P("}")/"")) local variableresolver = Cs((variable + P(1))^0) @@ -206,9 +218,12 @@ end function resolvers.newinstance() -- todo: all vars will become lowercase and alphanum only - if trace_locating then + -- normally we only need one instance but for special cases we can (re)load one so + -- we stick to this model. + + if trace_locating then report_resolving("creating instance") - end + end local environment, variables, expansions, order = allocate(), allocate(), allocate(), allocate() @@ -356,14 +371,14 @@ local function identify_configuration_files() for i=1,#cnfpaths do local filepath = cnfpaths[i] local filename = collapsepath(filejoin(filepath,luacnfname)) - local realname = resolvers.resolve(filename) -- can still have "//" ... needs checking + local realname = resolveprefix(filename) -- can still have "//" ... needs checking -- todo: environment.skipweirdcnfpaths directive if trace_locating then - local fullpath = gsub(resolvers.resolve(collapsepath(filepath)),"//","/") + local fullpath = gsub(resolveprefix(collapsepath(filepath)),"//","/") local weirdpath = find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c",1,true) report_resolving("looking for %a on %s path %a from specification %a",luacnfname,weirdpath and "weird" or "given",fullpath,filepath) end - if lfs.isfile(realname) then + if isfile(realname) then specification[#specification+1] = filename -- unresolved as we use it in matching, relocatable if trace_locating then report_resolving("found configuration file %a",realname) @@ -386,7 +401,7 @@ local function load_configuration_files() local filename = specification[i] local pathname = filedirname(filename) local filename = filejoin(pathname,luacnfname) - local realname = resolvers.resolve(filename) -- no shortcut + local realname = resolveprefix(filename) -- no shortcut local blob = loadfile(realname) if blob then local setups = instance.setups @@ -394,7 +409,7 @@ local function load_configuration_files() local parent = data and data.parent if parent then local filename = filejoin(pathname,parent) - local realname = resolvers.resolve(filename) -- no shortcut + local realname = resolveprefix(filename) -- no shortcut local blob = loadfile(realname) if blob then local parentdata = blob() @@ -419,7 +434,7 @@ local function load_configuration_files() elseif variables[k] == nil then if trace_locating and not warning then report_resolving("variables like %a in configuration file %a should move to the 'variables' subtable", - k,resolvers.resolve(filename)) + k,resolveprefix(filename)) warning = true end variables[k] = v @@ -492,7 +507,7 @@ local function locate_file_databases() local stripped = lpegmatch(inhibitstripper,path) -- the !! thing if stripped ~= "" then local runtime = stripped == path - path = resolvers.cleanpath(path) + path = cleanpath(path) local spec = resolvers.splitmethod(stripped) if runtime and (spec.noscheme or spec.scheme == "file") then stripped = "tree:///" .. stripped @@ -558,8 +573,8 @@ function resolvers.renew(hashname) report_resolving("identifying tree %a",hashname) end end - local realpath = resolvers.resolve(hashname) - if lfs.isdir(realpath) then + local realpath = resolveprefix(hashname) + if isdir(realpath) then if trace_locating then report_resolving("using path %a",realpath) end @@ -710,7 +725,7 @@ function resolvers.registerextrapath(paths,subpaths) local ps = p .. "/" .. s if not done[ps] then newn = newn + 1 - ep[newn] = resolvers.cleanpath(ps) + ep[newn] = cleanpath(ps) done[ps] = true end end @@ -720,7 +735,7 @@ function resolvers.registerextrapath(paths,subpaths) local p = paths[i] if not done[p] then newn = newn + 1 - ep[newn] = resolvers.cleanpath(p) + ep[newn] = cleanpath(p) done[p] = true end end @@ -732,7 +747,7 @@ function resolvers.registerextrapath(paths,subpaths) local ps = ep[i] .. "/" .. s if not done[ps] then newn = newn + 1 - ep[newn] = resolvers.cleanpath(ps) + ep[newn] = cleanpath(ps) done[ps] = true end end @@ -791,7 +806,7 @@ function resolvers.cleanpathlist(str) local t = resolvers.expandedpathlist(str) if t then for i=1,#t do - t[i] = collapsepath(resolvers.cleanpath(t[i])) + t[i] = collapsepath(cleanpath(t[i])) end end return t @@ -851,7 +866,7 @@ function resolvers.registerfilehash(name,content,someerror) end local function isreadable(name) - local readable = lfs.isfile(name) -- not file.is_readable(name) asit can be a dir + local readable = isfile(name) -- not file.is_readable(name) asit can be a dir if trace_detail then if readable then report_resolving("file %a is readable",name) @@ -862,75 +877,59 @@ local function isreadable(name) return readable end --- name --- name/name +-- name | name/name local function collect_files(names) - local filelist, noffiles = { }, 0 + local filelist = { } + local noffiles = 0 + local function check(hash,root,pathname,path,name) + if not pathname or find(path,pathname) then + local variant = hash.type + local search = filejoin(root,path,name) -- funny no concatinator + local result = methodhandler('concatinators',variant,root,path,name) + if trace_detail then + report_resolving("match: variant %a, search %a, result %a",variant,search,result) + end + noffiles = noffiles + 1 + filelist[noffiles] = { variant, search, result } + end + end for k=1,#names do - local fname = names[k] + local filename = names[k] if trace_detail then - report_resolving("checking name %a",fname) + report_resolving("checking name %a",filename) end - local bname = filebasename(fname) - local dname = filedirname(fname) - if dname == "" or find(dname,"^%.") then - dname = false + local basename = filebasename(filename) + local pathname = filedirname(filename) + if pathname == "" or find(pathname,"^%.") then + pathname = false else - dname = gsub(dname,"%*",".*") - dname = "/" .. dname .. "$" + pathname = gsub(pathname,"%*",".*") + pathname = "/" .. pathname .. "$" end local hashes = instance.hashes for h=1,#hashes do - local hash = hashes[h] - local blobpath = hash.name - local files = blobpath and instance.files[blobpath] - if files then + local hash = hashes[h] + local hashname = hash.name + local content = hashname and instance.files[hashname] + if content then if trace_detail then - report_resolving("deep checking %a, base %a, pattern %a",blobpath,bname,dname) - 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 + report_resolving("deep checking %a, base %a, pattern %a",blobpath,basename,pathname) end - if blobfile then - local blobroot = files.__path__ or blobpath - if type(blobfile) == 'string' then - if not dname or find(blobfile,dname) then - local variant = hash.type - -- local search = filejoin(blobpath,blobfile,bname) - local search = filejoin(blobroot,blobfile,bname) - local result = methodhandler('concatinators',hash.type,blobroot,blobfile,bname) - if trace_detail then - report_resolving("match: variant %a, search %a, result %a",variant,search,result) - end - noffiles = noffiles + 1 - filelist[noffiles] = { variant, search, result } - end + local path, name = lookup(content,basename) + if path then + local metadata = content.metadata + local realroot = metadata and metadata.path or hashname + if type(path) == "string" then + check(hash,realroot,pathname,path,name) else - for kk=1,#blobfile do - local vv = blobfile[kk] - if not dname or find(vv,dname) then - local variant = hash.type - -- local search = filejoin(blobpath,vv,bname) - local search = filejoin(blobroot,vv,bname) - local result = methodhandler('concatinators',hash.type,blobroot,vv,bname) - if trace_detail then - report_resolving("match: variant %a, search %a, result %a",variant,search,result) - end - noffiles = noffiles + 1 - filelist[noffiles] = { variant, search, result } - end + for i=1,#path do + check(hash,realroot,pathname,path[i],name) end end end elseif trace_locating then - report_resolving("no match in %a (%s)",blobpath,bname) + report_resolving("no match in %a (%s)",hashname,basename) end end end @@ -961,7 +960,7 @@ end local function can_be_dir(name) -- can become local local fakepaths = instance.fakepaths if not fakepaths[name] then - if lfs.isdir(name) then + if isdir(name) then fakepaths[name] = 1 -- directory else fakepaths[name] = 2 -- no directory @@ -987,10 +986,11 @@ local function find_analyze(filename,askedformat,allresults) if askedformat == "" then if ext == "" or not suffixmap[ext] then local defaultsuffixes = resolvers.defaultsuffixes + local formatofsuffix = resolvers.formatofsuffix for i=1,#defaultsuffixes do local forcedname = filename .. '.' .. defaultsuffixes[i] wantedfiles[#wantedfiles+1] = forcedname - filetype = resolvers.formatofsuffix(forcedname) + filetype = formatofsuffix(forcedname) if trace_locating then report_resolving("forcing filetype %a",filetype) end @@ -1032,7 +1032,7 @@ local function find_wildcard(filename,allresults) if trace_locating then report_resolving("checking wildcard %a", filename) end - local method, result = resolvers.findwildcardfiles(filename) + local result = resolvers.findwildcardfiles(filename) if result then return "wildcard", result end @@ -1040,7 +1040,7 @@ local function find_wildcard(filename,allresults) end local function find_qualified(filename,allresults,askedformat,alsostripped) -- this one will be split too - if not file.is_qualified_path(filename) then + if not is_qualified_path(filename) then return end if trace_locating then @@ -1152,7 +1152,6 @@ local function find_intree(filename,filetype,wantedfiles,allresults) if trace_detail then report_resolving("checking filename %a",filename) end - local resolve = resolvers.resolve local result = { } -- pathlist : resolved -- dirlist : unresolved or resolved @@ -1177,9 +1176,9 @@ local function find_intree(filename,filetype,wantedfiles,allresults) local f = fl[2] local d = dirlist[k] -- resolve is new: - if find(d,expression) or find(resolve(d),expression) then + if find(d,expression) or find(resolveprefix(d),expression) then -- todo, test for readable - result[#result+1] = resolve(fl[3]) -- no shortcut + result[#result+1] = resolveprefix(fl[3]) -- no shortcut done = true if allresults then if trace_detail then @@ -1201,7 +1200,7 @@ local function find_intree(filename,filetype,wantedfiles,allresults) else method = "filesystem" -- bonus, even when !! is specified pathname = gsub(pathname,"/+$","") - pathname = resolve(pathname) + pathname = resolveprefix(pathname) local scheme = url.hasscheme(pathname) if not scheme or scheme == "file" then local pname = gsub(pathname,"%.%*$",'') @@ -1299,7 +1298,7 @@ local function find_otherwise(filename,filetype,wantedfiles,allresults) -- other local filelist = collect_files(wantedfiles) local fl = filelist and filelist[1] if fl then - return "otherwise", { resolvers.resolve(fl[3]) } -- filename + return "otherwise", { resolveprefix(fl[3]) } -- filename end end @@ -1414,44 +1413,39 @@ function resolvers.findpath(filename,filetype) end local function findgivenfiles(filename,allresults) - local bname, result = filebasename(filename), { } - local hashes = instance.hashes - local noffound = 0 - for k=1,#hashes do - local hash = hashes[k] - local files = instance.files[hash.name] 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 + local base = filebasename(filename) + local result = { } + local hashes = instance.hashes + -- + local function okay(hash,path,name) + local found = methodhandler('concatinators',hash.type,hash.name,path,name) + if found and found ~= "" then + result[#result+1] = resolveprefix(found) + return not allresults end - if blist then - if type(blist) == 'string' then - local found = methodhandler('concatinators',hash.type,hash.name,blist,bname) or "" - if found ~= "" then - noffound = noffound + 1 - result[noffound] = resolvers.resolve(found) - if not allresults then - break - end + end + -- + for k=1,#hashes do + local hash = hashes[k] + local content = instance.files[hash.name] + if content then + local path, name = lookup(content,base) + if not path then + -- no match + elseif type(path) == "string" then + if okay(hash,path,name) then + return result end else - for kk=1,#blist do - local vv = blist[kk] - local found = methodhandler('concatinators',hash.type,hash.name,vv,bname) or "" - if found ~= "" then - noffound = noffound + 1 - result[noffound] = resolvers.resolve(found) - if not allresults then break end + for i=1,#path do + if okay(hash,path[i],name) then + return result end end end end end + -- return result end @@ -1463,37 +1457,6 @@ function resolvers.findgivenfile(filename) return findgivenfiles(filename,false)[1] or "" end -local function doit(path,blist,bname,tag,variant,result,allresults) - local done = false - if blist and variant then - local resolve = resolvers.resolve -- added - if type(blist) == 'string' then - -- make function and share code - if find(lower(blist),path) then - local full = methodhandler('concatinators',variant,tag,blist,bname) or "" - result[#result+1] = resolve(full) - done = true - end - else - for kk=1,#blist do - local vv = blist[kk] - if find(lower(vv),path) then - local full = methodhandler('concatinators',variant,tag,vv,bname) or "" - result[#result+1] = resolve(full) - done = true - if not allresults then break end - end - end - end - end - return done -end - ---~ local makewildcard = Cs( ---~ (P("^")^0 * P("/") * P(-1) + P(-1)) /".*" ---~ + (P("^")^0 * P("/") / "") * (P("*")/".*" + P("-")/"%%-" + P("?")/"."+ P("\\")/"/" + P(1))^0 ---~ ) - local makewildcard = Cs( (P("^")^0 * P("/") * P(-1) + P(-1)) /".*" + (P("^")^0 * P("/") / "")^0 * (P("*")/".*" + P("-")/"%%-" + P(".")/"%%." + P("?")/"."+ P("\\")/"/" + P(1))^0 @@ -1503,37 +1466,80 @@ function resolvers.wildcardpattern(pattern) return lpegmatch(makewildcard,pattern) or pattern end -local function findwildcardfiles(filename,allresults,result) -- todo: remap: and lpeg - result = result or { } ---~ local path = lower(lpegmatch(makewildcard,filedirname (filename))) ---~ local name = lower(lpegmatch(makewildcard,filebasename(filename))) - local base = filebasename(filename) - local dirn = filedirname(filename) - local path = lower(lpegmatch(makewildcard,dirn) or dirn) - local name = lower(lpegmatch(makewildcard,base) or base) - local files, done = instance.files, false +-- we use more function calls than before but we also have smaller trees so +-- why bother + +local function findwildcardfiles(filename,allresults,result) + local result = result or { } + local base = filebasename(filename) + local dirn = filedirname(filename) + local path = lower(lpegmatch(makewildcard,dirn) or dirn) + local name = lower(lpegmatch(makewildcard,base) or base) + local files = instance.files + -- if find(name,"*",1,true) then local hashes = instance.hashes + local function okay(found,path,base,hashname,hashtype) + if find(found,path) then + local full = methodhandler('concatinators',hashtype,hashname,found,base) + if full and full ~= "" then + result[#result+1] = resolveprefix(full) + return not allresults + end + end + end for k=1,#hashes do - local hash = hashes[k] - local hashname, hashtype = hash.name, hash.type - for kk, hh in next, files[hashname] do - if not find(kk,"^remap:") then - if find(lower(kk),name) then - if doit(path,hh,kk,hashname,hashtype,result,allresults) then done = true end - if done and not allresults then break end + local hash = hashes[k] + local hashname = hash.name + local hashtype = hash.type + if hashname and hashtype then + for found, base in filtered(files[hashname],name) do + if type(found) == 'string' then + if okay(found,path,base,hashname,hashtype) then + break + end + else + for i=1,#found do + if okay(found[i],path,base,hashname,hashtype) then + break + end + end end end end end else + local function okayokay(found,path,base,hashname,hashtype) + if find(found,path) then + local full = methodhandler('concatinators',hashtype,hashname,found,base) + if full and full ~= "" then + result[#result+1] = resolveprefix(full) + return not allresults + end + end + end + -- local hashes = instance.hashes --- inspect(hashes) for k=1,#hashes do - local hash = hashes[k] - local hashname, hashtype = hash.name, hash.type - if doit(path,files[hashname][base],base,hashname,hashtype,result,allresults) then done = true end - if done and not allresults then break end + local hash = hashes[k] + local hashname = hash.name + local hashtype = hash.type + if hashname and hashtype then + local found, base = lookup(content,base) + if not found then + -- nothing + elseif type(found) == 'string' then + if okay(found,path,base,hashname,hashtype) then + break + end + else + for i=1,#found do + if okay(found[i],path,base,hashname,hashtype) then + break + end + end + end + end end end -- we can consider also searching the paths not in the database, but then @@ -1626,7 +1632,7 @@ end function resolvers.dowithpath(name,func) local pathlist = resolvers.expandedpathlist(name) for i=1,#pathlist do - func("^"..resolvers.cleanpath(pathlist[i])) + func("^"..cleanpath(pathlist[i])) end end @@ -1636,23 +1642,23 @@ end function resolvers.locateformat(name) local engine = environment.ownmain or "luatex" - local barename = file.removesuffix(name) - local fullname = file.addsuffix(barename,"fmt") + local barename = removesuffix(name) + local fullname = addsuffix(barename,"fmt") local fmtname = caches.getfirstreadablefile(fullname,"formats",engine) or "" if fmtname == "" then fmtname = resolvers.findfile(fullname) - fmtname = resolvers.cleanpath(fmtname) + fmtname = cleanpath(fmtname) end if fmtname ~= "" then - local barename = file.removesuffix(fmtname) - local luaname = file.addsuffix(barename,luasuffixes.lua) - local lucname = file.addsuffix(barename,luasuffixes.luc) - local luiname = file.addsuffix(barename,luasuffixes.lui) - if lfs.isfile(luiname) then + local barename = removesuffix(fmtname) + local luaname = addsuffix(barename,luasuffixes.lua) + local lucname = addsuffix(barename,luasuffixes.luc) + local luiname = addsuffix(barename,luasuffixes.lui) + if isfile(luiname) then return barename, luiname - elseif lfs.isfile(lucname) then + elseif isfile(lucname) then return barename, lucname - elseif lfs.isfile(luaname) then + elseif isfile(luaname) then return barename, luaname end end @@ -1671,35 +1677,29 @@ end function resolvers.dowithfilesintree(pattern,handle,before,after) -- will move, can be a nice iterator instead local instance = resolvers.instance - local hashes = instance.hashes + local hashes = instance.hashes for i=1,#hashes do - local hash = hashes[i] + local hash = hashes[i] local blobtype = hash.type local blobpath = hash.name - if blobpath then + if blobtype and blobpath then + local total = 0 + local checked = 0 + local done = 0 if before then before(blobtype,blobpath,pattern) end - local files = instance.files[blobpath] - local total, checked, done = 0, 0, 0 - if files then - for k, v in table.sortedhash(files) do -- next, files do, beware: this is not the resolve order - total = total + 1 - if find(k,"^remap:") then - -- forget about these - elseif find(k,pattern) then - if type(v) == "string" then - checked = checked + 1 - if handle(blobtype,blobpath,v,k) then - done = done + 1 - end - else - checked = checked + #v - for i=1,#v do - if handle(blobtype,blobpath,v[i],k) then - done = done + 1 - end - end + for path, name in filtered(instance.files[blobpath],pattern) do + if type(path) == "string" then + checked = checked + 1 + if handle(blobtype,blobpath,path,name) then + done = done + 1 + end + else + checked = checked + #path + for i=1,#path do + if handle(blobtype,blobpath,path[i],name) then + done = done + 1 end end end @@ -1711,8 +1711,8 @@ function resolvers.dowithfilesintree(pattern,handle,before,after) -- will move, end end -resolvers.obsolete = resolvers.obsolete or { } -local obsolete = resolvers.obsolete +local obsolete = resolvers.obsolete or { } +resolvers.obsolete = obsolete resolvers.find_file = resolvers.findfile obsolete.find_file = resolvers.findfile resolvers.find_files = resolvers.findfiles obsolete.find_files = resolvers.findfiles diff --git a/tex/context/base/data-tmf.lua b/tex/context/base/data-tmf.lua index c52225193..e0ccac257 100644 --- a/tex/context/base/data-tmf.lua +++ b/tex/context/base/data-tmf.lua @@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['data-tmf'] = { license = "see context related readme files" } -local resolvers = resolvers +local resolvers = resolvers local report_tds = logs.reporter("resolvers","tds") diff --git a/tex/context/base/data-tmp.lua b/tex/context/base/data-tmp.lua index 3e109dcfe..8ee5792cc 100644 --- a/tex/context/base/data-tmp.lua +++ b/tex/context/base/data-tmp.lua @@ -35,6 +35,7 @@ local report_caches = logs.reporter("resolvers","caches") local report_resolvers = logs.reporter("resolvers","caching") local resolvers = resolvers +local cleanpath = resolvers.cleanpath -- intermezzo @@ -72,7 +73,7 @@ local writable, readables, usedreadables = nil, { }, { } local function identify() -- Combining the loops makes it messy. First we check the format cache path -- and when the last component is not present we try to create it. - local texmfcaches = resolvers.cleanpathlist("TEXMFCACHE") + local texmfcaches = resolvers.cleanpathlist("TEXMFCACHE") -- forward ref if texmfcaches then for k=1,#texmfcaches do local cachepath = texmfcaches[k] @@ -369,10 +370,12 @@ function caches.contentstate() return content_state or { } end -function caches.loadcontent(cachename,dataname) - local name = caches.hashed(cachename) - local full, path = caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") - local filename = file.join(path,name) +function caches.loadcontent(cachename,dataname,filename) + if not filename then + local name = caches.hashed(cachename) + local full, path = caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") + filename = file.join(path,name) + end local blob = loadfile(addsuffix(filename,luasuffixes.luc)) or loadfile(addsuffix(filename,luasuffixes.lua)) if blob then local data = blob() @@ -406,10 +409,12 @@ function caches.collapsecontent(content) end end -function caches.savecontent(cachename,dataname,content) - local name = caches.hashed(cachename) - local full, path = caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") - local filename = file.join(path,name) -- is full +function caches.savecontent(cachename,dataname,content,filename) + if not filename then + local name = caches.hashed(cachename) + local full, path = caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") + filename = file.join(path,name) -- is full + end local luaname = addsuffix(filename,luasuffixes.lua) local lucname = addsuffix(filename,luasuffixes.luc) if trace_locating then diff --git a/tex/context/base/data-tre.lua b/tex/context/base/data-tre.lua index 0a8b00d9b..3f11ca878 100644 --- a/tex/context/base/data-tre.lua +++ b/tex/context/base/data-tre.lua @@ -8,48 +8,60 @@ if not modules then modules = { } end modules ['data-tre'] = { -- \input tree://oeps1/**/oeps.tex -local find, gsub, format = string.find, string.gsub, string.format +local find, gsub, lower = string.find, string.gsub, string.lower +local basename, dirname, joinname = file.basename, file.dirname, file .join +local globdir, isdir = dir.glob, lfs.isdir local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end) -local report_trees = logs.reporter("resolvers","trees") +local report_trees = logs.reporter("resolvers","trees") -local resolvers = resolvers +local resolvers = resolvers +local resolveprefix = resolvers.resolve +local notfound = resolvers.finders.notfound -local done, found, notfound = { }, { }, resolvers.finders.notfound +-- A tree search is rather dumb ... there is some basic caching of searched trees +-- but nothing is cached over runs ... it's also a wildcard one so we cannot use +-- the normal scanner. -function resolvers.finders.tree(specification) +local collectors = { } +local found = { } + +function resolvers.finders.tree(specification) -- to be adapted to new formats local spec = specification.filename - local fnd = found[spec] - if fnd == nil then + local okay = found[spec] + if okay == nil then if spec ~= "" then - local path, name = file.dirname(spec), file.basename(spec) - if path == "" then path = "." end - local hash = done[path] - if not hash then - local pattern = path .. "/*" -- we will use the proper splitter - hash = dir.glob(pattern) - done[path] = hash + local path = dirname(spec) + local name = basename(spec) + if path == "" then + path = "." + end + local names = collectors[path] + if not names then + local pattern = find(path,"/%*+$") and path or (path .. "/*") + names = globdir(pattern) + collectors[path] = names end local pattern = "/" .. gsub(name,"([%.%-%+])", "%%%1") .. "$" - for k=1,#hash do - local v = hash[k] - if find(v,pattern) then - found[spec] = v - return v + for i=1,#names do + local fullname = names[i] + if find(fullname,pattern) then + found[spec] = fullname + return fullname end end end - fnd = notfound() -- false - found[spec] = fnd + okay = notfound() -- false + found[spec] = okay end - return fnd + return okay end function resolvers.locators.tree(specification) local name = specification.filename - local realname = resolvers.resolve(name) -- no shortcut - if realname and realname ~= '' and lfs.isdir(realname) then + local realname = resolveprefix(name) -- no shortcut + if realname and realname ~= '' and isdir(realname) then if trace_locating then report_trees("locator %a found",realname) end @@ -69,7 +81,56 @@ function resolvers.hashers.tree(specification) resolvers.generators.file(specification) end -resolvers.concatinators.tree = resolvers.concatinators.file -resolvers.generators.tree = resolvers.generators.file -resolvers.openers.tree = resolvers.openers.file -resolvers.loaders.tree = resolvers.loaders.file +-- This is a variation on tree lookups but this time we do cache in the given +-- root. We use a similar hasher as the resolvers because we have to deal with +-- for instance trees with 50K xml files plus a similar amount of resources to +-- deal and we don't want too much overhead. + +local collectors = { } + +table.setmetatableindex(collectors, function(t,k) + local rootname = gsub(k,"[/%*]+$","") + local dataname = joinname(rootname,"dirlist") + local data = caches.loadcontent(dataname,"files",dataname) + local content = data and data.content + local lookup = resolvers.get_from_content + if not content then + content = resolvers.scanfiles(rootname) + caches.savecontent(dataname,"files",content,dataname) + end + local files = content.files + local v = function(filename) + local path, name = lookup(content,filename) + if not path then + return filename + elseif type(path) == "table" then + -- maybe a warning that the first name is taken + path = path[1] + end + return joinname(rootname,path,name) + end + t[k] = v + return v +end) + +function resolvers.finders.dirlist(specification) -- can be called directly too + local spec = specification.filename + if spec ~= "" then + local path, name = dirname(spec), basename(spec) + return path and collectors[path](name) or notfound() + end + return notfound() +end + +resolvers.locators .dirlist = resolvers.locators .tree +resolvers.hashers .dirlist = resolvers.hashers .tree +resolvers.generators.dirlist = resolvers.generators.file +resolvers.openers .dirlist = resolvers.openers .file +resolvers.loaders .dirlist = resolvers.loaders .file + +-- local locate = collectors[ [[E:\temporary\mb-mp]] ] +-- local locate = collectors( [[\\storage-2\resources\mb-mp]] ) + +-- print(resolvers.findtexfile("tree://e:/temporary/mb-mp/**/VB_wmf_03_vw_01d_ant.jpg")) +-- print(resolvers.findtexfile("tree://t:/**/tufte.tex")) +-- print(resolvers.findtexfile("dirlist://e:/temporary/mb-mp/**/VB_wmf_03_vw_01d_ant.jpg")) diff --git a/tex/context/base/data-zip.lua b/tex/context/base/data-zip.lua index 5db69670c..a9d4d7a95 100644 --- a/tex/context/base/data-zip.lua +++ b/tex/context/base/data-zip.lua @@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['data-zip'] = { license = "see context related readme files" } --- partly redone .. needs testing +-- real old code ... partly redone .. needs testing due to changes as well as a decent overhaul local format, find, match = string.format, string.find, string.match @@ -64,7 +64,7 @@ function zip.openarchive(name) local arch = archives[name] if not arch then local full = resolvers.findfile(name) or "" - arch = (full ~= "" and zip.open(full)) or false + arch = full ~= "" and zip.open(full) or false archives[name] = arch end return arch @@ -235,30 +235,42 @@ function resolvers.usezipfile(archive) end function resolvers.registerzipfile(z,tree) - local files, filter = { }, "" - if tree == "" then - filter = "^(.+)/(.-)$" - else - filter = format("^%s/(.+)/(.-)$",tree) - end + local names = { } + local files = { } -- somewhat overkill .. todo + local remap = { } -- somewhat overkill .. todo + local n = 0 + local filter = tree == "" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree) + local register = resolvers.registerfile if trace_locating then report_zip("registering: using filter %a",filter) end - local register, n = resolvers.registerfile, 0 for i in z:files() do - local path, name = match(i.filename,filter) - if path then - if name and name ~= '' then - register(files, name, path) - n = n + 1 - else - -- directory + local filename = i.filename + local path, name = match(filename,filter) + if not path then + n = n + 1 + register(names,filename,"") + local usedname = lower(filename) + files[usedname] = "" + if usedname ~= filename then + remap[usedname] = filename end - else - register(files, i.filename, '') + elseif name and name ~= "" then n = n + 1 + register(names,name,path) + local usedname = lower(name) + files[usedname] = path + if usedname ~= name then + remap[usedname] = name + end + else + -- directory end end report_zip("registering: %s files registered",n) - return files + return { + -- metadata = { }, + files = files, + remap = remap, + } end diff --git a/tex/context/base/file-job.lua b/tex/context/base/file-job.lua index c88eb7e9d..ca0de2696 100644 --- a/tex/context/base/file-job.lua +++ b/tex/context/base/file-job.lua @@ -42,6 +42,7 @@ local is_qualified_path = file.is_qualified_path local cleanpath = resolvers.cleanpath local inputstack = resolvers.inputstack +local resolveprefix = resolvers.resolve local v_outer = variables.outer local v_text = variables.text @@ -535,7 +536,7 @@ local function process(what,name) local depth = #typestack local process -- - name = resolvers.resolve(name) + name = resolveprefix(name) -- -- if not tolerant then -- okay, would be best but not compatible with mkii diff --git a/tex/context/base/font-map.lua b/tex/context/base/font-map.lua index f74e13e81..e5f587105 100644 --- a/tex/context/base/font-map.lua +++ b/tex/context/base/font-map.lua @@ -149,6 +149,8 @@ local namesplitter = Ct(C((1 - ligseparator - varseparator)^1) * (ligseparator * -- print(string.formatters["%s: [% t]"](name,split)) -- end +-- maybe: ff fi fl ffi ffl => f_f f_i f_l f_f_i f_f_l + -- test("i.f_") -- test("this") -- test("this.that") diff --git a/tex/context/base/font-mis.lua b/tex/context/base/font-mis.lua index 7385d6f31..8debcc3bb 100644 --- a/tex/context/base/font-mis.lua +++ b/tex/context/base/font-mis.lua @@ -22,7 +22,7 @@ local handlers = fonts.handlers handlers.otf = handlers.otf or { } local otf = handlers.otf -otf.version = otf.version or 2.755 +otf.version = otf.version or 2.756 otf.cache = otf.cache or containers.define("fonts", "otf", otf.version, true) function otf.loadcached(filename,format,sub) diff --git a/tex/context/base/font-otf.lua b/tex/context/base/font-otf.lua index 0a5d1cfea..ed9cabedc 100644 --- a/tex/context/base/font-otf.lua +++ b/tex/context/base/font-otf.lua @@ -48,7 +48,7 @@ local otf = fonts.handlers.otf otf.glists = { "gsub", "gpos" } -otf.version = 2.755 -- beware: also sync font-mis.lua +otf.version = 2.756 -- beware: also sync font-mis.lua otf.cache = containers.define("fonts", "otf", otf.version, true) local fontdata = fonts.hashes.identifiers @@ -1473,6 +1473,14 @@ actions["reorganize lookups"] = function(data,filename,raw) -- we could check fo rule.current = s_hashed(names,s_h_cache) end rule.glyphs = nil + local lookups = rule.lookups + if lookups then + for i=1,#names do + if not lookups[i] then + lookups[i] = "" -- fix sparse array + end + end + end end end end diff --git a/tex/context/base/font-syn.lua b/tex/context/base/font-syn.lua index 18ed46a2f..a1bee5d54 100644 --- a/tex/context/base/font-syn.lua +++ b/tex/context/base/font-syn.lua @@ -33,7 +33,7 @@ local exists = io.exists local findfile = resolvers.findfile local cleanpath = resolvers.cleanpath -local resolveresolved = resolvers.resolve +local resolveprefix = resolvers.resolve local settings_to_hash = utilities.parsers.settings_to_hash_tolerant @@ -1065,15 +1065,15 @@ local function analyzefiles(olddata) resolvers.dowithfilesintree(".*%." .. suffix .. "$", function(method,root,path,name) if method == "file" or method == "tree" then local completename = root .."/" .. path .. "/" .. name - completename = resolveresolved(completename) -- no shortcut + completename = resolveprefix(completename) -- no shortcut identify(completename,name,suffix,name) return true end end, function(blobtype,blobpath,pattern) - blobpath = resolveresolved(blobpath) -- no shortcut + blobpath = resolveprefix(blobpath) -- no shortcut report_names("scanning path %a for %s files",blobpath,suffix) end, function(blobtype,blobpath,pattern,total,checked,done) - blobpath = resolveresolved(blobpath) -- no shortcut + blobpath = resolveprefix(blobpath) -- no shortcut report_names("%s entries found, %s %s files checked, %s okay",total,checked,suffix,done) end) end diff --git a/tex/context/base/l-dir.lua b/tex/context/base/l-dir.lua index 257212060..660529baf 100644 --- a/tex/context/base/l-dir.lua +++ b/tex/context/base/l-dir.lua @@ -9,7 +9,7 @@ if not modules then modules = { } end modules ['l-dir'] = { -- dir.expandname will be merged with cleanpath and collapsepath local type, select = type, select -local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub +local find, gmatch, match, gsub, sub = string.find, string.gmatch, string.match, string.gsub, string.sub local concat, insert, remove, unpack = table.concat, table.insert, table.remove, table.unpack local lpegmatch = lpeg.match @@ -21,8 +21,8 @@ local lfs = lfs local attributes = lfs.attributes local walkdir = lfs.dir -local isdir = lfs.isdir -local isfile = lfs.isfile +local isdir = lfs.isdir -- not robust, will be overloaded anyway +local isfile = lfs.isfile -- not robust, will be overloaded anyway local currentdir = lfs.currentdir local chdir = lfs.chdir local mkdir = lfs.mkdir @@ -31,20 +31,36 @@ local onwindows = os.type == "windows" or find(os.getenv("PATH"),";",1,true) -- in case we load outside luatex -if not isdir then - function isdir(name) - local a = attributes(name) - return a and a.mode == "directory" +if onwindows then + + -- lfs.isdir does not like trailing / + -- lfs.dir accepts trailing / + + isdir = function(name) + name = gsub(name,"([/\\]+)$","/.") + return attributes(name,"mode") == "directory" end - lfs.isdir = isdir -end -if not isfile then - function isfile(name) - local a = attributes(name) - return a and a.mode == "file" + isfile = function(name) + return attributes(name,"mode") == "file" + end + + lfs.isdir = isdir + lfs.isfile = isfile + +else + + isdir = function(name) + return attributes(name,"mode") == "directory" end + + isfile = function(name) + return attributes(name,"mode") == "file" + end + + lfs.isdir = isdir lfs.isfile = isfile + end -- handy @@ -53,63 +69,104 @@ function dir.current() return (gsub(currentdir(),"\\","/")) end --- optimizing for no find (*) does not save time - ---~ local function globpattern(path,patt,recurse,action) -- fails in recent luatex due to some change in lfs ---~ 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 ---~ globpattern(full,patt,recurse,action) ---~ end ---~ end ---~ end ---~ end - -local lfsisdir = isdir - -local function isdir(path) - path = gsub(path,"[/\\]+$","") - return lfsisdir(path) -end +-- somewhat optimized -lfs.isdir = isdir +local function glob_pattern_function(path,patt,recurse,action) + if isdir(path) then + local usedpath + if path == "/" then + usedpath = "/." + elseif not find(path,"/$") then + usedpath = path .. "/." + path = path .. "/" + else + usedpath = path + end + local dirs + for name in walkdir(usedpath) do + if name ~= "." and name ~= ".." then + local full = path .. name + local mode = attributes(full,'mode') + if mode == 'file' then + if not patt or find(full,patt) then + action(full) + end + elseif recurse and mode == "directory" then + if not dirs then + dirs = { full } + else + dirs[#dirs+1] = full + end + end + end + end + if dirs then + for i=1,#dirs do + glob_pattern_function(dirs[i],patt,recurse,action) + end + end + end +end -local function globpattern(path,patt,recurse,action) - if path == "/" then - path = path .. "." - elseif not find(path,"/$") then - path = path .. '/' +local function glob_pattern_table(path,patt,recurse,result) + if not result then + result = { } end - if isdir(path) then -- lfs.isdir does not like trailing / - for name in walkdir(path) do -- lfs.dir accepts trailing / - local full = path .. name - local mode = attributes(full,'mode') - if mode == 'file' then - if find(full,patt) then - action(full) + if isdir(path) then + local usedpath + if path == "/" then + usedpath = "/." + elseif not find(path,"/$") then + usedpath = path .. "/." + path = path .. "/" + else + usedpath = path + end + local dirs + for name in walkdir(usedpath) do + if name ~= "." and name ~= ".." then + local full = path .. name + local mode = attributes(full,'mode') + if mode == 'file' then + if not patt or find(full,patt) then + result[#result+1] = full + end + elseif recurse and mode == "directory" then + if not dirs then + dirs = { full } + else + dirs[#dirs+1] = full + end end - elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then - globpattern(full,patt,recurse,action) end end + if dirs then + for i=1,#dirs do + glob_pattern_table(dirs[i],patt,recurse,result) + end + end + end + return result +end + +local function globpattern(path,patt,recurse,method) + local kind = type(method) + if pattern and sub(patt,1,-3) == path then + patt = false + end + if kind == "function" then + return glob_pattern_function(path,patt,recurse,method) + elseif kind == "table" then + return glob_pattern_table(path,patt,recurse,method) + else + return glob_pattern_table(path,patt,recurse,{ }) end end dir.globpattern = globpattern +-- never or seldom used so far: + local function collectpattern(path,patt,recurse,result) local ok, scanner result = result or { } @@ -119,18 +176,26 @@ local function collectpattern(path,patt,recurse,result) ok, scanner, first = 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 + if not find(path,"/$") then + path = path .. '/' + end for name in scanner, first do - local full = path .. name - local attr = attributes(full) - local mode = attr.mode - if mode == 'file' then - if find(full,patt) then + if name == "." then + -- skip + elseif name == ".." then + -- skip + else + 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" then + attr.list = collectpattern(full,patt,recurse) result[name] = attr end - elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then - attr.list = collectpattern(full,patt,recurse) - result[name] = attr end end end @@ -143,15 +208,10 @@ local separator if onwindows then -- we could sanitize here --- pattern = Ct { --- [1] = (C(P(".") + S("/\\")^1) + C(R("az","AZ") * P(":") * S("/\\")^0) + Cc("./")) * V(2) * V(3), --- [2] = C(((1-S("*?/\\"))^0 * S("/\\"))^0), --- [3] = C(P(1)^0) --- } - local slash = S("/\\") / "/" - pattern = Ct { +-- pattern = Ct { + pattern = { [1] = (Cs(P(".") + slash^1) + Cs(R("az","AZ") * P(":") * slash^0) + Cc("./")) * V(2) * V(3), [2] = Cs(((1-S("*?/\\"))^0 * slash)^0), [3] = Cs(P(1)^0) @@ -159,7 +219,8 @@ if onwindows then -- we could sanitize here else -- assume unix - pattern = Ct { +-- pattern = Ct { + pattern = { [1] = (C(P(".") + P("/")^1) + Cc("./")) * V(2) * V(3), [2] = C(((1-S("*?/"))^0 * P("/"))^0), [3] = C(P(1)^0) @@ -186,12 +247,11 @@ local function glob(str,t) elseif isfile(str) then t(str) else - local split = lpegmatch(pattern,str) -- we could use the file splitter - if split then - local root, path, base = split[1], split[2], split[3] + local root, path, base = lpegmatch(pattern,str) -- we could use the file splitter + if root and path and base then local recurse = find(base,"**",1,true) -- find(base,"%*%*") - local start = root .. path - local result = lpegmatch(filter,start .. base) + local start = root .. path + local result = lpegmatch(filter,start .. base) globpattern(start,result,recurse,t) end end @@ -210,16 +270,12 @@ local function glob(str,t) return { str } end else - local split = lpegmatch(pattern,str) -- we could use the file splitter - 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,"**",1,true) -- find(base,"%*%*") - local start = root .. path - local result = lpegmatch(filter,start .. base) - globpattern(start,result,recurse,action) - return t + local root, path, base = lpegmatch(pattern,str) -- we could use the file splitter + if root and path and base then + local recurse = find(base,"**",1,true) -- find(base,"%*%*") + local start = root .. path + local result = lpegmatch(filter,start .. base) + return globpattern(start,result,recurse,t) else return { } end @@ -229,11 +285,20 @@ 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 c = os.clock() +-- local t = dir.glob("e:/**") +-- local t = dir.glob("t:/sources/**") +-- local t = dir.glob("t:/**") +-- print(os.clock()-c,#t) + +-- for i=1,3000 do print(t[i]) end +-- for i=1,10 do print(t[i]) end + +-- 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 @@ -275,10 +340,10 @@ function dir.ls(pattern) return concat(glob(pattern),"\n") end ---~ mkdirs("temp") ---~ mkdirs("a/b/c") ---~ mkdirs(".","/a/b/c") ---~ mkdirs("a","b","c") +-- mkdirs("temp") +-- mkdirs("a/b/c") +-- mkdirs(".","/a/b/c") +-- mkdirs("a","b","c") local make_indeed = true -- false @@ -347,17 +412,17 @@ if onwindows then return pth, (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/")) + -- 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/")) else @@ -408,13 +473,13 @@ else return pth, (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/")) + -- 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/")) end @@ -424,7 +489,7 @@ dir.makedirs = dir.mkdirs if onwindows then - function dir.expandname(str) -- will be merged with cleanpath and collapsepath + function dir.expandname(str) -- will be merged with cleanpath and collapsepath\ local first, nothing, last = match(str,"^(//)(//*)(.*)$") if first then first = dir.current() .. "/" -- dir.current sanitizes diff --git a/tex/context/base/l-table.lua b/tex/context/base/l-table.lua index ea675b081..ca067fb1e 100644 --- a/tex/context/base/l-table.lua +++ b/tex/context/base/l-table.lua @@ -164,14 +164,14 @@ local function sortedhash(t,cmp) end local n = 0 local m = #s - local function kv(s) + local function kv() -- (s) if n < m then n = n + 1 local k = s[n] return k, t[k] end end - return kv, s + return kv -- , s else return nothing end @@ -1114,3 +1114,49 @@ function table.values(t,s) -- optional sort flag return { } end end + +-- maybe this will move to util-tab.lua + +-- for k, v in table.filtered(t,pattern) do ... end +-- for k, v in table.filtered(t,pattern,true) do ... end +-- for k, v in table.filtered(t,pattern,true,cmp) do ... end + +function table.filtered(t,pattern,sort,cmp) + if t and type(pattern) == "string" then + if sort then + local s + if cmp then + -- it would be nice if the sort function would accept a third argument (or nicer, an optional first) + s = sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) + else + s = sortedkeys(t) -- the robust one + end + local n = 0 + local m = #s + local function kv(s) + while n < m do + n = n + 1 + local k = s[n] + if find(k,pattern) then + return k, t[k] + end + end + end + return kv, s + else + local n = next(t) + local function iterator() + while n do + local k = n + n = next(t,k) + if find(k,pattern) then + return k, t[k] + end + end + end + return iterator, t + end + else + return nothing + end +end diff --git a/tex/context/base/lpdf-fmt.lua b/tex/context/base/lpdf-fmt.lua index 568b801b4..9a5005782 100644 --- a/tex/context/base/lpdf-fmt.lua +++ b/tex/context/base/lpdf-fmt.lua @@ -710,7 +710,9 @@ function codeinjections.setformat(s) end end function codeinjections.setformat(noname) - report_backend("error, format is already set to %a, ignoring %a",formatname,noname.format) + if trace_format then + report_backend("error, format is already set to %a, ignoring %a",formatname,noname.format) + end end else report_backend("error, format %a is not supported",format) diff --git a/tex/context/base/lpdf-pda.xml b/tex/context/base/lpdf-pda.xml index 2d8e7b6f5..3f6b969c0 100644 --- a/tex/context/base/lpdf-pda.xml +++ b/tex/context/base/lpdf-pda.xml @@ -3,15 +3,20 @@ <!-- lpdf-pda.xml --> <x:xmpmeta xmlns:x="adobe:ns:meta/"> + <!-- http://www.pdfa.org/wp-content/uploads/2011/08/tn0008_predefined_xmp_properties_in_pdfa-1_2008-03-20.pdf --> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/"> <dc:format>application/pdf</dc:format> <dc:creator> <rdf:Seq> - <rdf:li/> + <rdf:li xml:lang="x-default"/> </rdf:Seq> </dc:creator> - <dc:description/> + <dc:description> + <rdf:Alt> + <rdf:li xml:lang="x-default"/> + </rdf:Alt> + </dc:description> <dc:title> <rdf:Alt> <rdf:li xml:lang="x-default"/> diff --git a/tex/context/base/lpdf-pdx.xml b/tex/context/base/lpdf-pdx.xml index 42e11650e..d55e1fdf3 100644 --- a/tex/context/base/lpdf-pdx.xml +++ b/tex/context/base/lpdf-pdx.xml @@ -8,10 +8,14 @@ <dc:format>application/pdf</dc:format> <dc:creator> <rdf:Seq> - <rdf:li/> + <rdf:li xml:lang="x-default"/> </rdf:Seq> </dc:creator> - <dc:description/> + <dc:description> + <rdf:Alt> + <rdf:li xml:lang="x-default"/> + </rdf:Alt> + </dc:description> <dc:title> <rdf:Alt> <rdf:li xml:lang="x-default"/> diff --git a/tex/context/base/lpdf-xmp.lua b/tex/context/base/lpdf-xmp.lua index c8b2d236c..739b29ef7 100644 --- a/tex/context/base/lpdf-xmp.lua +++ b/tex/context/base/lpdf-xmp.lua @@ -26,7 +26,7 @@ local pdfconstant = lpdf.constant local pdfreference = lpdf.reference local pdfflushstreamobject = lpdf.flushstreamobject --- I wonder why this begin end is empty / w (no time now to look into it) +-- I wonder why this begin end is empty / w (no time now to look into it) / begin can also be "?" local xpacket = [[ <?xpacket begin="" id="%s"?> @@ -50,7 +50,7 @@ local mapping = { -- Dublin Core schema ["Author"] = "rdf:Description/dc:creator/rdf:Seq/rdf:li", ["Format"] = "rdf:Description/dc:format", -- optional, but nice to have - ["Subject"] = "rdf:Description/dc:description", + ["Subject"] = "rdf:Description/dc:description/rdf:Alt/rdf:li", ["Title"] = "rdf:Description/dc:title/rdf:Alt/rdf:li", -- XMP Basic schema ["CreateDate"] = "rdf:Description/xmp:CreateDate", @@ -105,7 +105,7 @@ local function valid_xmp() if xmpfile ~= "" then report_xmp("using file %a",xmpfile) end - local xmpdata = (xmpfile ~= "" and io.loaddata(xmpfile)) or "" + local xmpdata = xmpfile ~= "" and io.loaddata(xmpfile) or "" xmp = xml.convert(xmpdata) end return xmp diff --git a/tex/context/base/lxml-tex.lua b/tex/context/base/lxml-tex.lua index 98f154b13..700259f4e 100644 --- a/tex/context/base/lxml-tex.lua +++ b/tex/context/base/lxml-tex.lua @@ -19,6 +19,8 @@ local P, S, C, Cc = lpeg.P, lpeg.S, lpeg.C, lpeg.Cc local tex, xml = tex, xml local lowerchars, upperchars, lettered = characters.lower, characters.upper, characters.lettered +local basename, dirname, joinfile = file.basename, file.dirname, file.join + lxml = lxml or { } local lxml = lxml @@ -39,24 +41,28 @@ local xmlunprivatized, xmlprivatetoken, xmlprivatecodes = xml.unprivatized, xml. local xmlstripelement = xml.stripelement local xmlinclusion, xmlinclusions = xml.inclusion, xml.inclusions -local variables = interfaces and interfaces.variables or { } +local variables = interfaces and interfaces.variables or { } local settings_to_hash = utilities.parsers.settings_to_hash local insertbeforevalue = utilities.tables.insertbeforevalue local insertaftervalue = utilities.tables.insertaftervalue -local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming +local resolveprefix = resolvers.resolve + +local starttiming = statistics.starttiming +local stoptiming = statistics.stoptiming -local trace_setups = false trackers.register("lxml.setups", function(v) trace_setups = v end) -local trace_loading = false trackers.register("lxml.loading", function(v) trace_loading = v end) -local trace_access = false trackers.register("lxml.access", function(v) trace_access = v end) -local trace_comments = false trackers.register("lxml.comments", function(v) trace_comments = v end) -local trace_entities = false trackers.register("xml.entities", function(v) trace_entities = v end) +local trace_setups = false trackers.register("lxml.setups", function(v) trace_setups = v end) +local trace_loading = false trackers.register("lxml.loading", function(v) trace_loading = v end) +local trace_access = false trackers.register("lxml.access", function(v) trace_access = v end) +local trace_comments = false trackers.register("lxml.comments", function(v) trace_comments = v end) +local trace_entities = false trackers.register("xml.entities", function(v) trace_entities = v end) -local report_lxml = logs.reporter("xml","tex") -local report_xml = logs.reporter("xml","tex") +local report_lxml = logs.reporter("xml","tex") +local report_xml = logs.reporter("xml","tex") -local forceraw, rawroot = false, nil +local forceraw = false +local forceraw = nil -- tex entities -- @@ -437,37 +443,6 @@ function lxml.register(id,xmltable,filename) return xmltable end --- function lxml.include(id,pattern,attribute,recurse,resolve) --- starttiming(xml) --- local root = getid(id) --- xml.include(root,pattern,attribute,recurse,function(filename) --- if filename then --- -- preprocessing --- filename = commands.preparedfile(filename) --- -- some protection --- if file.dirname(filename) == "" and root.filename then --- local dn = file.dirname(root.filename) --- if dn ~= "" then --- filename = file.join(dn,filename) --- end --- end --- if trace_loading then --- report_lxml("including file %a",filename) --- end --- -- handy if we have a flattened structure --- if resolve then --- filename = resolvers.resolve(filename) or filename --- end --- -- todo: check variants and provide --- noffiles, nofconverted = noffiles + 1, nofconverted + 1 --- return resolvers.loadtexfile(filename) or "" --- else --- return "" --- end --- end) --- stoptiming(xml) --- end - -- recurse prepare rootpath resolve basename local options_true = { "recurse", "prepare", "rootpath" } @@ -493,17 +468,17 @@ function lxml.include(id,pattern,attribute,options) end -- handy if we have a flattened structure if options.basename then - filename = file.basename(filename) + filename = basename(filename) end if options.resolve then - filename = resolvers.resolve(filename) or filename + filename = resolveprefix(filename) or filename end -- some protection if options.rootpath then - if file.dirname(filename) == "" and root.filename then - local dn = file.dirname(root.filename) + if dirname(filename) == "" and root.filename then + local dn = dirname(root.filename) if dn ~= "" then - filename = file.join(dn,filename) + filename = joinfile(dn,filename) end end end diff --git a/tex/context/base/mlib-lua.lua b/tex/context/base/mlib-lua.lua index e3a3ba5d8..fae915c98 100644 --- a/tex/context/base/mlib-lua.lua +++ b/tex/context/base/mlib-lua.lua @@ -21,6 +21,8 @@ local report_luarun = logs.reporter("metapost","lua") local trace_luarun = false trackers.register("metapost.lua",function(v) trace_luarun = v end) local trace_enabled = true +local be_tolerant = true directives.register("metapost.lua.tolerant",function(v) be_tolerant = v end) + mp = mp or { } -- system namespace MP = MP or { } -- user namespace @@ -146,14 +148,52 @@ local f_code = formatters["%s return mp._f_()"] local cache, n = { }, 0 -- todo: when > n then reset cache or make weak +-- function metapost.runscript(code) +-- if trace_enabled and trace_luarun then +-- report_luarun("code: %s",code) +-- end +-- local f +-- if n > 100 then +-- cache = nil -- forget about caching +-- f = loadstring(f_code(code)) +-- else +-- f = cache[code] +-- if not f then +-- f = loadstring(f_code(code)) +-- if f then +-- n = n + 1 +-- cache[code] = f +-- end +-- end +-- end +-- if f then +-- local result = f() +-- if result then +-- local t = type(result) +-- if t == "number" then +-- return f_numeric(result) +-- elseif t == "string" then +-- return result +-- else +-- return tostring(result) +-- end +-- end +-- end +-- return "" +-- end + function metapost.runscript(code) - if trace_enabled and trace_luarun then + local trace = trace_enabled and trace_luarun + if trace then report_luarun("code: %s",code) end local f if n > 100 then cache = nil -- forget about caching f = loadstring(f_code(code)) + if not f and be_tolerant then + f = loadstring(code) + end else f = cache[code] if not f then @@ -161,6 +201,12 @@ function metapost.runscript(code) if f then n = n + 1 cache[code] = f + elseif be_tolerant then + f = loadstring(code) + if f then + n = n + 1 + cache[code] = f + end end end end @@ -169,13 +215,21 @@ function metapost.runscript(code) if result then local t = type(result) if t == "number" then - return f_numeric(result) + t = f_numeric(result) elseif t == "string" then - return result + t = result else - return tostring(result) + t = tostring(result) end + if trace then + report_luarun("result: %s",code) + end + return t + elseif trace then + report_luarun("no result") end + else + report_luarun("no result, invalid code") end return "" end @@ -208,5 +262,8 @@ mp.number = mp.numeric function metapost.initializescriptrunner(mpx,trialrun) currentmpx = mpx - trace_enabled = not trialrun + if trace_luarun then + report_luarun("type of run: %s", trialrun and "trial" or "final") + end + -- trace_enabled = not trialrun blocks too much end diff --git a/tex/context/base/mult-low.lua b/tex/context/base/mult-low.lua index d9cc167d8..3728b0433 100644 --- a/tex/context/base/mult-low.lua +++ b/tex/context/base/mult-low.lua @@ -142,7 +142,7 @@ return { "startcontextdefinitioncode", "stopcontextdefinitioncode", "texdefinition", -- - "doifsetupselse", "doifsetups", "doifnotsetups", "setup", "setups", "texsetup", "xmlsetup", "luasetup", "directsetup", + "doifsetupselse", "doifsetups", "doifnotsetups", "setup", "setups", "texsetup", "xmlsetup", "luasetup", "directsetup", "fastsetup", "doifelsecommandhandler","doifnotcommandhandler","doifcommandhandler", -- "newmode", "setmode", "resetmode", diff --git a/tex/context/base/publ-aut.lua b/tex/context/base/publ-aut.lua index 72766763d..b35af1bcc 100644 --- a/tex/context/base/publ-aut.lua +++ b/tex/context/base/publ-aut.lua @@ -11,12 +11,13 @@ if not characters then dofile(resolvers.findfile("char-ini.lua")) end +local lpeg = lpeg + local context = context local chardata = characters.data local tostring = tostring local concat = table.concat -local lpeg = lpeg local utfchar = utf.char local formatters = string.formatters @@ -204,6 +205,8 @@ local function splitauthorstring(str) return authors end +authors.splitstring = splitauthorstring + -- local function splitauthors(dataset,tag,field) -- local entries = datasets[dataset] -- local luadata = entries.luadata @@ -214,214 +217,38 @@ end -- if not entry then -- return { } -- end --- return splitauthorstring(entry[field]) +-- return splitauthorstring(entry[field]) -- end local function the_initials(initials,symbol) - local t, symbol = { }, symbol or "." - for i=1,#initials do - t[i] = initials[i] .. symbol - end - return t -end - --- authors - -local settings = { } - --- local defaultsettings = { --- firstnamesep = " ", --- initialsep = " ", --- vonsep = " ", --- surnamesep = " ", --- juniorsep = " ", --- surnamejuniorsep = ", ", --- juniorjuniorsep = ", ", --- surnamefirstnamesep = ", ", --- surnameinitialsep = ", ", --- namesep = ", ", --- lastnamesep = " and ", --- finalnamesep = " and ", --- etallimit = 1000, --- etaldisplay = 1000, --- etaltext = "", --- } - -local defaultsettings = { - firstnamesep = [[\btxlistvariantparameter{firstnamesep}]], - vonsep = [[\btxlistvariantparameter{vonsep}]], - surnamesep = [[\btxlistvariantparameter{surnamesep}]], - juniorsep = [[\btxlistvariantparameter{juniorsep}]], - surnamejuniorsep = [[\btxlistvariantparameter{surnamejuniorsep}]], - juniorjuniorsep = [[\btxlistvariantparameter{juniorjuniorsep}]], - surnamefirstnamesep = [[\btxlistvariantparameter{surnamefirstnamesep}]], - surnameinitialsep = [[\btxlistvariantparameter{surnameinitialsep}]], - initialsep = [[\btxlistvariantparameter{initialsep}]], - namesep = [[\btxlistvariantparameter{namesep}]], - lastnamesep = [[\btxlistvariantparameter{lastnamesep}]], - finalnamesep = [[\btxlistvariantparameter{finalnamesep}]], - -- - etaltext = [[\btxlistvariantparameter{etaltext}]], - -- - etallimit = 1000, - etaldisplay = 1000, -} - -function authors.setsettings(s) -end - -authors.splitstring = splitauthorstring - --- [firstnames] [firstnamesep] [vons] [vonsep] [surnames] [juniors] [surnamesep] (Taco, von Hoekwater, jr) - -function authors.normal(author,settings) - local firstnames, vons, surnames, juniors = author.firstnames, author.vons, author.surnames, author.juniors - local result, settings = { }, settings or defaultsettings - if firstnames and #firstnames > 0 then - result[#result+1] = concat(firstnames," ") - result[#result+1] = settings.firstnamesep or defaultsettings.firstnamesep - end - if vons and #vons > 0 then - result[#result+1] = concat(vons," ") - result[#result+1] = settings.vonsep or defaultsettings.vonsep - end - if surnames and #surnames > 0 then - result[#result+1] = concat(surnames," ") - if juniors and #juniors > 0 then - result[#result+1] = settings.surnamejuniorsep or defaultsettings.surnamejuniorsep - result[#result+1] = concat(juniors," ") - end - elseif juniors and #juniors > 0 then - result[#result+1] = concat(juniors," ") - end - return concat(result) -end - --- [initials] [initialsep] [vons] [vonsep] [surnames] [juniors] [surnamesep] (T, von Hoekwater, jr) - -function authors.normalshort(author,settings) - local initials, vons, surnames, juniors = author.initials, author.vons, author.surnames, author.juniors - local result, settings = { }, settings or defaultsettings - if initials and #initials > 0 then - result[#result+1] = concat(the_initials(initials)," ") - result[#result+1] = settings.initialsep or defaultsettings.initialsep - end - if vons and #vons > 0 then - result[#result+1] = concat(vons," ") - result[#result+1] = settings.vonsep or defaultsettings.vonsep - end - if surnames and #surnames > 0 then - result[#result+1] = concat(surnames," ") - if juniors and #juniors > 0 then - result[#result+1] = settings.surnamejuniorsep or defaultsettings.surnamejuniorsep - result[#result+1] = concat(juniors," ") - end - elseif juniors and #juniors > 0 then - result[#result+1] = concat(juniors," ") - end - return concat(result) -end - --- [vons] [vonsep] [surnames] [surnamejuniorsep] [juniors] [surnamefirstnamesep] [firstnames] (von Hoekwater jr, Taco) - -function authors.inverted(author,settings) - local firstnames, vons, surnames, juniors = author.firstnames, author.vons, author.surnames, author.juniors - local result, settings = { }, settings or defaultsettings - if vons and #vons > 0 then - result[#result+1] = concat(vons," ") - result[#result+1] = settings.vonsep or defaultsettings.vonsep - end - if surnames and #surnames > 0 then - result[#result+1] = concat(surnames," ") - if juniors and #juniors > 0 then - result[#result+1] = settings.surnamejuniorsep or defaultsettings.surnamejuniorsep - result[#result+1] = concat(juniors," ") - end - elseif juniors and #juniors > 0 then - result[#result+1] = concat(juniors," ") - end - if firstnames and #firstnames > 0 then - result[#result+1] = settings.surnamefirstnamesep or defaultsettings.surnamefirstnamesep - result[#result+1] = concat(firstnames," ") - end - return concat(result) -end - --- [vons] [vonsep] [surnames] [surnamejuniorsep] [juniors] [surnamefirstnamesep] [initials] (von Hoekwater jr, T) - -function authors.invertedshort(author,settings) - local vons, surnames, initials, juniors = author.vons, author.surnames, author.initials, author.juniors - local result, settings = { }, settings or defaultsettings - if vons and #vons > 0 then - result[#result+1] = concat(vons," ") - result[#result+1] = settings.vonsep or defaultsettings.vonsep - end - if surnames and #surnames > 0 then - result[#result+1] = concat(surnames," ") - if juniors and #juniors > 0 then - result[#result+1] = settings.surnamejuniorsep or defaultsettings.surnamejuniorsep - result[#result+1] = concat(juniors," ") - end - elseif juniors and #juniors > 0 then - result[#result+1] = concat(juniors," ") - end - if initials and #initials > 0 then - result[#result+1] = settings.surnameinitialsep or defaultsettings.surnameinitialsep - result[#result+1] = concat(the_initials(initials)," ") - end - return concat(result) -end - --- [vons] [vonsep] [surnames] - -function authors.name(author,settings) - local vons, surnames = author.vons, author.surnames - local result, settings = { }, settings or defaultsettings - if vons and #vons > 0 then - result[#result+1] = concat(vons," ") - result[#result+1] = settings.vonsep or defaultsettings.vonsep - end - if surnames and #surnames > 0 then - result[#result+1] = concat(surnames," ") - if juniors and #juniors > 0 then - result[#result+1] = settings.surnamejuniorsep or defaultsettings.surnamejuniorsep - result[#result+1] = concat(juniors," ") - end - end - return concat(result) -end - -local lastconcatsize = 1 - -local function concatnames(t,settings) - local namesep = settings.namesep - local lastnamesep = settings.lastnamesep - local finalnamesep = settings.finalnamesep - local lastconcatsize = #t - if lastconcatsize > 2 then - local s = { } - for i=1,lastconcatsize-2 do - s[i] = t[i] .. namesep - end - s[lastconcatsize-1], s[lastconcatsize] = t[lastconcatsize-1] .. finalnamesep, t[lastconcatsize] - return concat(s) - elseif lastconcatsize > 1 then - return concat(t,lastnamesep) - elseif lastconcatsize > 0 then - return t[1] + if not symbol or symbol == "" then + return initials else - return "" + local result = { } + for i=1,#initials do + result[i] = initials[i] .. symbol + end + return result end end -local f_invalid = formatters["<invalid %s: %s>"] - -function authors.concat(dataset,tag,field,settings) - table.setmetatableindex(settings,defaultsettings) - local combiner = settings.combiner - if not combiner or type(combiner) == "string" then - combiner = authors[combiner or "normal"] or authors.normal - end +local ctx_btxsetconcat = context.btxsetconcat +local ctx_btxsetoverflow = context.btxsetoverflow +local ctx_btxsetinitials = context.btxsetinitials +local ctx_btxsetfirstnames = context.btxsetfirstnames +local ctx_btxsetvons = context.btxsetvons +local ctx_btxsetsurnames = context.btxsetsurnames +local ctx_btxsetjuniors = context.btxsetjuniors +local ctx_btxciteauthorsetup = context.btxciteauthorsetup +local ctx_btxlistauthorsetup = context.btxlistauthorsetup +local ctx_btxsetauthorvariant = context.btxsetauthorvariant +local ctx_btxstartauthor = context.btxstartauthor +local ctx_btxstopauthor = context.btxstopauthor + +local concatstate = publications.concatstate +local f_invalid = formatters["<invalid %s: %s>"] + +function commands.btxauthor(dataset,tag,field,settings) local ds = datasets[dataset] if not ds then return f_invalid("dataset",dataset) @@ -434,31 +261,58 @@ function authors.concat(dataset,tag,field,settings) if not split then return f_invalid("field",field) end - local etallimit = settings.etallimit or 1000 - local etaldisplay = settings.etaldisplay or etallimit local max = split and #split or 0 if max == 0 then -- error end + local etallimit = tonumber(settings.etallimit) or 1000 + local etaldisplay = tonumber(settings.etaldisplay) or etallimit + local combiner = settings.combiner + local symbol = settings.symbol + if not combiner or combiner == "" then + combiner = "normal" + end + if not symbol then + symbol = "." + end + local ctx_btxsetup = settings.kind == "cite" and ctx_btxciteauthorsetup or ctx_btxlistauthorsetup if max > etallimit and etaldisplay < max then max = etaldisplay end - local combined = { } for i=1,max do - combined[i] = combiner(split[i],settings) + ctx_btxstartauthor() -- i, max + ctx_btxsetconcat(concatstate(i,max)) + ctx_btxsetauthorvariant(combiner) + local author = split[i] + local initials = author.initials + if initials then + ctx_btxsetinitials(concat(the_initials(initials,symbol)," ")) + end + local firstnames = author.firstnames + if firstnames then + ctx_btxsetfirstnames(concat(firstnames," ")) + end + local vons = author.vons + if vons then + ctx_btxsetvons(concat(vons," ")) + end + local surnames = author.surnames + if surnames then + ctx_btxsetsurnames(concat(surnames," ")) + end + local juniors = author.juniors + if juniors then + ctx_btxsetjuniors(concat(juniors," ")) + end + ctx_btxsetup(combiner) + ctx_btxstopauthor() end - local result = concatnames(combined,settings) - if #combined <= max then - return result - else - return result .. settings.etaltext + local overflow = max - #split + if overflow > 0 then + ctx_btxsetoverflow(overflow) end end -function commands.btxauthor(...) - context(authors.concat(...)) -end - -- We can consider creating a hashtable key -> entry but I wonder if -- pays off. diff --git a/tex/context/base/publ-dat.lua b/tex/context/base/publ-dat.lua index fdb77b6d3..986ef75c2 100644 --- a/tex/context/base/publ-dat.lua +++ b/tex/context/base/publ-dat.lua @@ -639,3 +639,19 @@ end -- print(table.serialize(dataset.xmldata)) -- print(table.serialize(dataset.shortcuts)) -- print(xml.serialize(dataset.xmldata)) + +-- a helper: + +function publications.concatstate(i,n) + if i == 0 then + return 0 + elseif i == 1 then + return 1 + elseif i == 2 and n == 2 then + return 4 + elseif i == n then + return 3 + else + return 2 + end +end diff --git a/tex/context/base/publ-imp-author.mkvi b/tex/context/base/publ-imp-author.mkvi new file mode 100644 index 000000000..e21353f63 --- /dev/null +++ b/tex/context/base/publ-imp-author.mkvi @@ -0,0 +1,278 @@ +%D \module +%D [ file=publ-imp-author, +%D version=2014.06.23, +%D title=\CONTEXT\ Publication Support, +%D subtitle=Authors, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\unprotect + +% We can do a better check for pre-sep-post at the lua end but by keeping it at the +% tex end users can easier mess with it. So, we just assume sane names. +% +% maybe cite will just inherit from list (only \current.. alias) +% +% \startsetups \s!btx:\s!cite:\s!author:normal +% \fastsetup{\s!btx:\s!list:\s!author:normal} +% \stopsetups + +% You can adapt these setups to your liking, for instance as: + +% \startsetups btx:cite:author:normal +% \fastsetup{btx:cite:author:concat} +% \ifx\currentbtxfirstnames\empty \else +% \begingroup +% \bf +% \currentbtxfirstnames +% \endgroup +% \btxcitevariantparameter{firstnamesep} +% \fi +% \ifx\currentbtxvons\empty \else +% \currentbtxvons +% \btxcitevariantparameter{vonsep} +% \fi +% \ifx\currentbtxsurnames\empty \else +% \currentbtxsurnames +% \ifx\currentbtxjuniors\empty \else +% \btxcitevariantparameter{juniorsep} +% \currentbtxjuniors +% \fi +% \fi +% \fastsetup{btx:cite:author:etaltext} +% \stopsetups + +\startsetups \s!btx:\s!cite:\s!author:concat + \ifcase\currentbtxconcat \or \or + \btxcitevariantparameter\c!namesep + \or + \btxcitevariantparameter\c!lastnamesep + \or + \btxcitevariantparameter\c!finalnamesep + \fi +\stopsetups + +\startsetups \s!btx:\s!cite:\s!author:etaltext + \ifcase\currentbtxoverflow \else + \btxcitevariantparameter\c!etaltext + \fi +\stopsetups + +\startsetups \s!btx:\s!cite:\s!author:normal + \fastsetup{\s!btx:\s!cite:\s!author:concat} + \ifx\currentbtxfirstnames\empty \else + \currentbtxfirstnames + \btxcitevariantparameter\c!firstnamesep + \fi + \ifx\currentbtxvons\empty \else + \currentbtxvons + \ifx\currentbtxsurnames\empty \else + \btxcitevariantparameter\c!vonsep + \fi + \fi + \ifx\currentbtxsurnames\empty \else + \currentbtxsurnames + \ifx\currentbtxjuniors\empty \else + \btxcitevariantparameter\c!juniorsep + \currentbtxjuniors + \fi + \fi + \fastsetup{\s!btx:\s!cite:\s!author:etaltext} +\stopsetups + +\startsetups \s!btx:\s!cite:\s!author:normalshort + \fastsetup{\s!btx:\s!cite:\s!author:concat} + \ifx\currentbtxinitials\empty \else + \currentbtxinitials + \btxcitevariantparameter\c!initialsep + \fi + \ifx\currentbtxvons\empty \else + \currentbtxvons + \ifx\currentbtxsurnames\empty \else + \btxcitevariantparameter\c!vonsep + \fi + \fi + \ifx\currentbtxsurnames\empty \else + \currentbtxsurnames + \ifx\currentbtxjuniors\empty \else + \btxcitevariantparameter\c!juniorsep + \currentbtxjuniors + \fi + \fi + \fastsetup{\s!btx:\s!cite:\s!author:etaltext} +\stopsetups + +\startsetups \s!btx:\s!cite:\s!author:inverted + \fastsetup{\s!btx:\s!cite:\s!author:concat} + \ifx\currentbtxvons\empty \else + \currentbtxvons + \btxcitevariantparameter\c!vonsep + \fi + \ifx\currentbtxsurnames\empty \else + \currentbtxsurnames + \ifx\currentbtxjuniors\empty \else + \btxcitevariantparameter\c!juniorsep + \currentbtxjuniors + \fi + \fi + \ifx\currentbtxfirstnames\empty + % firstnames are optional + \else + \btxcitevariantparameter\c!surnamefirstnamesep + \currentbtxfirstnames + \fi + \fastsetup{\s!btx:\s!cite:\s!author:etaltext} +\stopsetups + +\startsetups \s!btx:\s!cite:\s!author:invertedshort + \fastsetup{\s!btx:\s!cite:\s!author:concat} + \ifx\currentbtxvons\empty \else + \currentbtxvons + \btxcitevariantparameter\c!vonsep + \fi + \ifx\currentbtxsurnames\empty \else + \currentbtxsurnames + \ifx\currentbtxjuniors\empty \else + \btxcitevariantparameter\c!juniorsep + \currentbtxjuniors + \fi + \fi + \ifx\currentbtxinitials\empty + % initials are optional + \else + \btxcitevariantparameter\c!surnameinitialsep + \currentbtxinitials + \fi + \fastsetup{\s!btx:\s!cite:\s!author:etaltext} +\stopsetups + +\startsetups \s!btx:\s!cite:\s!author:name + \fastsetup{\s!btx:\s!cite:\s!author:concat} + \ifx\currentbtxvons\empty \else + \currentbtxvons + \btxcitevariantparameter\c!vonsep + \fi + \currentbtxsurnames + \fastsetup{\s!btx:\s!cite:\s!author:etaltext} +\stopsetups + +% list (mostly the same) + +\startsetups \s!btx:\s!list:\s!author:concat + \ifcase\currentbtxconcat \or \or + \btxlistvariantparameter\c!namesep + \or + \btxlistvariantparameter\c!lastnamesep + \or + \btxlistvariantparameter\c!finalnamesep + \fi +\stopsetups + +\startsetups \s!btx:\s!list:\s!author:etaltext + \btxcitevariantparameter\c!etaltext +\stopsetups + +\startsetups \s!btx:\s!list:\s!author:normal + \fastsetup{\s!btx:\s!list:\s!author:concat} + \ifx\currentbtxfirstnames\empty \else + \currentbtxfirstnames + \btxlistvariantparameter\c!firstnamesep + \fi + \ifx\currentbtxvons\empty \else + \currentbtxvons + \ifx\currentbtxsurnames\empty \else + \btxlistvariantparameter\c!vonsep + \fi + \fi + \ifx\currentbtxsurnames\empty \else + \currentbtxsurnames + \ifx\currentbtxjuniors\empty \else + \btxlistvariantparameter\c!juniorsep + \currentbtxjuniors + \fi + \fi + \fastsetup{\s!btx:\s!list:\s!author:etaltext} +\stopsetups + +\startsetups \s!btx:\s!list:\s!author:normalshort + \fastsetup{\s!btx:\s!list:\s!author:concat} + \ifx\currentbtxinitials\empty \else + \currentbtxinitials + \btxlistvariantparameter\c!initialsep + \fi + \ifx\currentbtxvons\empty \else + \currentbtxvons + \ifx\currentbtxsurnames\empty \else + \btxlistvariantparameter\c!vonsep + \fi + \fi + \ifx\currentbtxsurnames\empty \else + \currentbtxsurnames + \ifx\currentbtxjuniors\empty \else + \btxlistvariantparameter\c!juniorsep + \currentbtxjuniors + \fi + \fi + \fastsetup{\s!btx:\s!list:\s!author:etaltext} +\stopsetups + +\startsetups \s!btx:\s!list:\s!author:inverted + \fastsetup{\s!btx:\s!list:\s!author:concat} + \ifx\currentbtxvons\empty \else + \currentbtxvons + \btxlistvariantparameter\c!vonsep + \fi + \ifx\currentbtxsurnames\empty \else + \currentbtxsurnames + \ifx\currentbtxjuniors\empty \else + \btxlistvariantparameter\c!juniorsep + \currentbtxjuniors + \fi + \fi + \ifx\currentbtxfirstnames\empty + % firstnames are optional + \else + \btxlistvariantparameter\c!surnamefirstnamesep + \currentbtxfirstnames + \fi + \fastsetup{\s!btx:\s!list:\s!author:etaltext} +\stopsetups + +\startsetups \s!btx:\s!list:\s!author:invertedshort + \fastsetup{\s!btx:\s!list:\s!author:concat} + \ifx\currentbtxvons\empty \else + \currentbtxvons + \btxlistvariantparameter\c!vonsep + \fi + \ifx\currentbtxsurnames\empty \else + \currentbtxsurnames + \ifx\currentbtxjuniors\empty \else + \btxlistvariantparameter\c!juniorsep + \currentbtxjuniors + \fi + \fi + \ifx\currentbtxinitials\empty + % initials are optional + \else + \btxlistvariantparameter\c!surnameinitialsep + \currentbtxinitials + \fi + \fastsetup{\s!btx:\s!list:\s!author:etaltext} +\stopsetups + +\startsetups \s!btx:\s!list:\s!author:name + \fastsetup{\s!btx:\s!list:\s!author:concat} + \ifx\currentbtxvons\empty \else + \currentbtxvons + \btxlistvariantparameter\c!vonsep + \fi + \currentbtxsurnames + \fastsetup{\s!btx:\s!list:\s!author:etaltext} +\stopsetups + +\protect diff --git a/tex/context/base/publ-imp-cite.mkvi b/tex/context/base/publ-imp-cite.mkvi index 1580062bf..6ef584699 100644 --- a/tex/context/base/publ-imp-cite.mkvi +++ b/tex/context/base/publ-imp-cite.mkvi @@ -59,7 +59,7 @@ \startsetups \s!btx:\s!cite:common:normal \ifx\currentbtxfirst\empty - \directsetup{\s!btx:\s!cite:\s!unknown} + \fastsetup{\s!btx:\s!cite:\s!unknown} \else\ifx\currentbtxsecond\empty \btxcitereference \currentbtxfirst @@ -73,7 +73,7 @@ \startsetups \s!btx:\s!cite:common:range \ifx\currentbtxfirst\empty - \directsetup{\s!btx:\s!cite:\s!unknown} + \fastsetup{\s!btx:\s!cite:\s!unknown} \else\ifx\currentbtxsecond\empty \btxcitereference \currentbtxfirst @@ -96,9 +96,9 @@ \stopsetups \startsetups \s!btx:\s!cite:render:normal - \directsetup{\s!btx:\s!cite:concat} + \fastsetup{\s!btx:\s!cite:concat} \ifx\currentbtxfirst\empty - \directsetup{\s!btx:\s!cite:\s!unknown} + \fastsetup{\s!btx:\s!cite:\s!unknown} \else \texdefinition {btx:cite:inject} { \btxcitereference @@ -112,9 +112,9 @@ \stopsetups \startsetups \s!btx:\s!cite:render:range - \directsetup{\s!btx:\s!cite:concat} + \fastsetup{\s!btx:\s!cite:concat} \ifx\currentbtxfirst\empty - \directsetup{\s!btx:\s!cite:missing} + \fastsetup{\s!btx:\s!cite:missing} \else \texdefinition {btx:cite:inject} { \btxcitereference @@ -128,103 +128,101 @@ \stopsetups \startsetups \s!btx:\s!cite:render:variant - \directsetup{\s!btx:\s!cite:concat} + \fastsetup{\s!btx:\s!cite:concat} \texdefinition {btx:cite:inject} { - \directsetup{\s!btx:\s!cite:render:\currentbtxcitevariant} + \fastsetup{\s!btx:\s!cite:render:\currentbtxcitevariant} } \stopsetups -% author lists: can be less - \startsetups \s!btx:\s!cite:common:author \ifx\currentbtxfirst\empty - \directsetup{\s!btx:\s!cite:\s!unknown} - \else\ifx\currentbtxcitevariant\v!normal - \btxcitereference - \currentbtxfirst + \fastsetup{\s!btx:\s!cite:\s!unknown} \else \btxcitereference - \currentbtxciteauthor - \fi\fi + \currentbtxfirst + \fi \ifx\currentbtxsecond\empty \else + \relax % keeps a following space \btxcitevariantparameter\v!inbetween \currentbtxsecond \fi \stopsetups +% one level will be removed + \startsetups \s!btx:\s!cite:render:author - \directsetup{\s!btx:\s!cite:common:author} + \fastsetup{\s!btx:\s!cite:common:author} \stopsetups \startsetups \s!btx:\s!cite:render:authoryear - \directsetup{\s!btx:\s!cite:common:author} + \fastsetup{\s!btx:\s!cite:common:author} \stopsetups \startsetups \s!btx:\s!cite:render:authoryears - \directsetup{\s!btx:\s!cite:common:author} + \fastsetup{\s!btx:\s!cite:common:author} \stopsetups \startsetups \s!btx:\s!cite:render:authornum - \directsetup{\s!btx:\s!cite:common:author} + \fastsetup{\s!btx:\s!cite:common:author} \stopsetups \startsetups \s!btx:\s!cite:author:num - \directsetup{\s!btx:\s!cite:render:range} + \fastsetup{\s!btx:\s!cite:render:range} \stopsetups \startsetups \s!btx:\s!cite:author:year - \directsetup{\s!btx:\s!cite:render:range} + \fastsetup{\s!btx:\s!cite:render:range} \stopsetups \startsetups \s!btx:\s!cite:author:years - \directsetup{\s!btx:\s!cite:render:range} + \fastsetup{\s!btx:\s!cite:render:range} \stopsetups \startsetups \s!btx:\s!cite:author - \directsetup{\s!btx:\s!cite:render:variant} + \fastsetup{\s!btx:\s!cite:render:variant} \stopsetups \startsetups \s!btx:\s!cite:authoryear - \directsetup{\s!btx:\s!cite:render:variant} + \fastsetup{\s!btx:\s!cite:render:variant} \stopsetups \startsetups \s!btx:\s!cite:authoryears - \directsetup{\s!btx:\s!cite:render:variant} + \fastsetup{\s!btx:\s!cite:render:variant} \stopsetups \startsetups \s!btx:\s!cite:authornum - \directsetup{\s!btx:\s!cite:render:variant} + \fastsetup{\s!btx:\s!cite:render:variant} \stopsetups \startsetups \s!btx:\s!cite:year - \directsetup{\s!btx:\s!cite:render:range} + \fastsetup{\s!btx:\s!cite:render:range} \stopsetups \startsetups \s!btx:\s!cite:short - \directsetup{\s!btx:\s!cite:render:normal} + \fastsetup{\s!btx:\s!cite:render:normal} \stopsetups \startsetups \s!btx:\s!cite:serial - \directsetup{\s!btx:\s!cite:render:range} + \fastsetup{\s!btx:\s!cite:render:range} \stopsetups \startsetups \s!btx:\s!cite:tag - \directsetup{\s!btx:\s!cite:render:normal} + \fastsetup{\s!btx:\s!cite:render:normal} \stopsetups \startsetups \s!btx:\s!cite:key - \directsetup{\s!btx:\s!cite:render:normal} + \fastsetup{\s!btx:\s!cite:render:normal} \stopsetups %startsetups \s!btx:\s!cite:doi -% \directsetup{\s!btx:\s!cite:render:normal} +% \fastsetup{\s!btx:\s!cite:render:normal} %stopsetups %startsetups \s!btx:\s!cite:url -% \directsetup{\s!btx:\s!cite:render:normal} +% \fastsetup{\s!btx:\s!cite:render:normal} %stopsetups \startsetups \s!btx:\s!cite:category - \directsetup{\s!btx:\s!cite:render:normal} + \fastsetup{\s!btx:\s!cite:render:normal} \stopsetups \startsetups \s!btx:\s!cite:type - \directsetup{\s!btx:\s!cite:render:normal} + \fastsetup{\s!btx:\s!cite:render:normal} \stopsetups \startsetups \s!btx:\s!cite:num - \directsetup{\s!btx:\s!cite:render:range} + \fastsetup{\s!btx:\s!cite:render:range} \stopsetups \startsetups \s!btx:\s!cite:page - \directsetup{\s!btx:\s!cite:render:normal} + \fastsetup{\s!btx:\s!cite:render:normal} \stopsetups \startsetups \s!btx:\s!cite:render:doi \ifx\currentbtxfirst\empty - \directsetup{\s!btx:\s!cite:\s!unknown} + \fastsetup{\s!btx:\s!cite:\s!unknown} \else \btxcitereference \hyphenatedurl{\currentbtxfirst} @@ -233,7 +231,7 @@ \startsetups \s!btx:\s!cite:url \ifx\currentbtxfirst\empty - \directsetup{\s!btx:\s!cite:\s!unknown} + \fastsetup{\s!btx:\s!cite:\s!unknown} \else\ifconditional\btxinteractive \goto { \btxcitereference diff --git a/tex/context/base/publ-ini.lua b/tex/context/base/publ-ini.lua index d88c3e381..4d4c9ef09 100644 --- a/tex/context/base/publ-ini.lua +++ b/tex/context/base/publ-ini.lua @@ -90,12 +90,10 @@ local ctx_firstoftwoarguments = context.firstoftwoarguments local ctx_secondoftwoarguments = context.secondoftwoarguments local ctx_firstofoneargument = context.firstofoneargument local ctx_gobbleoneargument = context.gobbleoneargument ------ ctx_directsetup = context.directsetup local ctx_btxlistparameter = context.btxlistparameter local ctx_btxcitevariantparameter = context.btxcitevariantparameter local ctx_btxlistvariantparameter = context.btxlistvariantparameter ------ ctx_btxdomarkcitation = context.btxdomarkcitation local ctx_btxdirectlink = context.btxdirectlink local ctx_btxhandlelistentry = context.btxhandlelistentry local ctx_btxchecklistentry = context.btxchecklistentry @@ -107,7 +105,6 @@ local ctx_btxmissing = context.btxmissing local ctx_btxsetdataset = context.btxsetdataset local ctx_btxsettag = context.btxsettag local ctx_btxsetlanguage = context.btxsetlanguage -local ctx_btxsetindex = context.btxsetindex local ctx_btxsetcombis = context.btxsetcombis local ctx_btxsetcategory = context.btxsetcategory local ctx_btxcitesetup = context.btxcitesetup @@ -117,8 +114,12 @@ local ctx_btxsetinternal = context.btxsetinternal local ctx_btxsetbacklink = context.btxsetbacklink local ctx_btxsetbacktrace = context.btxsetbacktrace local ctx_btxsetcount = context.btxsetcount ------ ctx_btxsetrealpage = context.btxsetrealpage local ctx_btxsetconcat = context.btxsetconcat +local ctx_btxsetoveflow = context.btxsetoverflow +local ctx_btxstartcite = context.btxstartcite +local ctx_btxstopcite = context.btxstopcite +local ctx_btxstartciteauthor = context.btxstartciteauthor +local ctx_btxstopciteauthor = context.btxstopciteauthor local ctx_btxstartsubcite = context.btxstartsubcite local ctx_btxstopsubcite = context.btxstopsubcite local ctx_btxlistsetup = context.btxlistsetup @@ -442,33 +443,24 @@ local function findallused(dataset,reference,internal) return okay, todo, tags end -local function flushcollected(reference,flush,nofcollected) - if nofcollected > 0 then - flush(1,1) - if nofcollected > 2 then - for i=2,nofcollected-1 do - flush(i,2) - end - flush(nofcollected,3) - elseif nofcollected > 1 then - flush(nofcollected,4) - end - else - ctx_btxsettag(reference) - ctx_btxcitesetup("unknown") - end +local function unknowncite(reference) + ctx_btxsettag(reference) + ctx_btxcitesetup("unknown") end +local concatstate = publications.concatstate + local tobemarked = nil function marknocite(dataset,tag,nofcitations) -- or just: ctx_btxdomarkcitation - ctx_btxsetdataset(dataset) - ctx_btxsettag(tag) - ctx_btxsetbacklink(nofcitations) - ctx_btxcitesetup("nocite") + ctx_btxstartcite() + ctx_btxsetdataset(dataset) + ctx_btxsettag(tag) + ctx_btxsetbacklink(nofcitations) + ctx_btxcitesetup("nocite") + ctx_btxstopcite() end - local function markcite(dataset,tag,flush) if not tobemarked then return 0 @@ -1169,7 +1161,6 @@ function lists.flushentries(dataset,sorttype) local tag = li[1] local entry = luadata[tag] if entry and (forceall or repeated or not used[tag]) then - ctx_btxsetindex(i) local combined = entry.combined if combined then ctx_btxsetcombis(concat(combined,",")) @@ -1448,9 +1439,10 @@ local function processcite(dataset,reference,mark,compress,setup,internal,getter source[i] = data end - local function flushindeed(state,entry,tag) + local function flush(i,n,entry,tag) local tag = tag or entry.tag local currentcitation = markcite(dataset,tag) + ctx_btxstartcite() ctx_btxsettag(tag) ctx_btxsetbacklink(currentcitation) local bl = listtocite[currentcitation] @@ -1468,27 +1460,36 @@ local function processcite(dataset,reference,mark,compress,setup,internal,getter if not setter(entry,entry.last) then ctx_btxsetfirst(f_missing(tag)) end - ctx_btxsetconcat(state) + ctx_btxsetconcat(concatstate(i,n)) ctx_btxcitesetup(setup) + ctx_btxstopcite() end if compress and not badkey then local target = (compressor or compresslist)(source) - local function flush(i,state) - local entry = target[i] - local first = entry.first - if first then - flushindeed(state,first,list[1]) -- somewhat messy as we can be sorted so this needs checking! might be wrong - else - flushindeed(state,entry) + local nofcollected = #target + if nofcollected == 0 then + unknowncite(reference) + else + for i=1,nofcollected do + local entry = target[i] + local first = entry.first + if first then + flush(i,nofcollected,first,list[1]) -- somewhat messy as we can be sorted so this needs checking! might be wrong + else + flush(i,nofcollected,entry) + end end end - flushcollected(reference,flush,#target) else - local function flush(i,state) - flushindeed(state,source[i]) + local nofcollected = #source + if nofcollected == 0 then + unknowncite(reference) + else + for i=1,nofcollected do + flush(i,nofcollected,source[i]) + end end - flushcollected(reference,flush,#source) end end if tobemarked then @@ -1713,26 +1714,6 @@ function citevariants.tag(dataset,reference,mark,compress,variant,internal) return processcite(dataset,reference,mark,compress,"tag",internal,setter,getter) end --- author - -local function setter(dataset,tag,entry,internal) - return { - dataset = dataset, - tag = tag, - internal = internal, - author = getfield(dataset,tag,"author"), - } -end - -local function getter(first,last) - ctx_btxsetfirst(first.author) -- todo: formatted - return true -end - -function citevariants.author(dataset,reference,mark,compress,variant,internal) - processcite(dataset,reference,mark,false,"author",internal,setter,getter) -end - -- todo : sort -- todo : choose between publications or commands namespace -- todo : use details.author @@ -1743,6 +1724,11 @@ end -- common +local currentbtxciteauthor = function() + context.currentbtxciteauthor() + return true -- needed? +end + local function authorcompressor(found) local result = { } local entries = { } @@ -1775,43 +1761,50 @@ local function authorcompressor(found) end local function authorconcat(target,key,setup) - local function flush(i,state) - local entry = target[i] - local first = entry.first - local tag = entry.tag - local currentcitation = markcite(entry.dataset,tag) - ctx_btxsettag(tag) - ctx_btxsetbacklink(currentcitation) - local bl = listtocite[currentcitation] - ctx_btxsetinternal(bl and bl.references.internal or "") - if first then - ctx_btxsetfirst(first[key] or f_missing(first.tag)) - local suffix = entry.suffix - local value = entry.last[key] - if suffix then - ctx_btxsetsecond(value .. converters.characters(suffix)) - else - ctx_btxsetsecond(value) - end - else - local suffix = entry.suffix - local value = entry[key] or f_missing(tag) - if suffix then - ctx_btxsetfirst(value .. converters.characters(suffix)) + ctx_btxstartsubcite(setup) + local nofcollected = #target + if nofcollected == 0 then + unknowncite(tag) + else + for i=1,nofcollected do + local entry = target[i] + local first = entry.first + local tag = entry.tag + local currentcitation = markcite(entry.dataset,tag) + ctx_btxstartciteauthor() + ctx_btxsettag(tag) + ctx_btxsetbacklink(currentcitation) + local bl = listtocite[currentcitation] + ctx_btxsetinternal(bl and bl.references.internal or "") + if first then + ctx_btxsetfirst(first[key] or f_missing(first.tag)) + local suffix = entry.suffix + local value = entry.last[key] + if suffix then + ctx_btxsetsecond(value .. converters.characters(suffix)) + else + ctx_btxsetsecond(value) + end else - ctx_btxsetfirst(value) + local suffix = entry.suffix + local value = entry[key] or f_missing(tag) + if suffix then + ctx_btxsetfirst(value .. converters.characters(suffix)) + else + ctx_btxsetfirst(value) + end end + ctx_btxsetconcat(concatstate(i,nofcollected)) + ctx_btxcitesetup(setup) + ctx_btxstopciteauthor() end - ctx_btxsetconcat(state) - ctx_btxcitesetup(setup) end - ctx_btxstartsubcite(setup) - flushcollected(setup,flush,#target) ctx_btxstopsubcite() end local function authorsingle(entry,key,setup) ctx_btxstartsubcite(setup) + ctx_btxstartciteauthor() local tag = entry.tag ctx_btxsettag(tag) -- local currentcitation = markcite(entry.dataset,tag) @@ -1820,13 +1813,15 @@ local function authorsingle(entry,key,setup) -- ctx_btxsetinternal(bl and bl.references.internal or "") ctx_btxsetfirst(entry[key] or f_missing(tag)) ctx_btxcitesetup(setup) + ctx_btxstopciteauthor() ctx_btxstopsubcite() end local partialinteractive = false local function authorgetter(first,last,key,setup) -- only first - ctx_btxsetfirst(first.author) -- todo: reformat + -- ctx_btxsetfirst(first.author) -- unformatted + ctx_btxsetfirst(currentbtxciteauthor) -- formatter (much slower) local entries = first.entries -- alternatively we can use a concat with one ... so that we can only make the -- year interactive, as with the concat @@ -1835,15 +1830,38 @@ local function authorgetter(first,last,key,setup) -- only first end if entries then local c = compresslist(entries) + local f = function() authorconcat(c,key,setup) return true end -- indeed return true? ctx_btxsetcount(#c) - ctx_btxsetsecond(function() authorconcat(c,key,setup) return true end) -- indeed return true? + ctx_btxsetsecond(f) else + local f = function() authorsingle(first,key,setup) return true end -- indeed return true? ctx_btxsetcount(0) - ctx_btxsetsecond(function() authorsingle(first,key,setup) return true end) -- indeed return true? + ctx_btxsetsecond(f) end return true end +-- author + +local function setter(dataset,tag,entry,internal) + return { + dataset = dataset, + tag = tag, + internal = internal, + author = getfield(dataset,tag,"author"), + } +end + +local function getter(first,last,_,setup) + -- ctx_btxsetfirst(first.author) -- unformatted + ctx_btxsetfirst(currentbtxciteauthor) -- formatter (much slower) + return true +end + +function citevariants.author(dataset,reference,mark,compress,variant,internal) + processcite(dataset,reference,mark,false,"author",internal,setter,getter) +end + -- authornum local function setter(dataset,tag,entry,internal) @@ -1864,7 +1882,7 @@ local function getter(first,last) end local function compressor(found) - return authorcompressor(found) + return authorcompressor(found) -- can be just an alias end function citevariants.authornum(dataset,reference,mark,compress,variant,internal) diff --git a/tex/context/base/publ-ini.mkiv b/tex/context/base/publ-ini.mkiv index e32e99114..5f8e335fe 100644 --- a/tex/context/base/publ-ini.mkiv +++ b/tex/context/base/publ-ini.mkiv @@ -52,6 +52,7 @@ \def\s!cite {cite} \def\s!nocite {nocite} \def\s!list {list} +\def\s!author {author} \def\v!btxcite {btxcite} \def\v!btxlist {btxlist} \def\v!btxrendering {btxrendering} @@ -94,24 +95,11 @@ \unexpanded\def\stopbtxlistentry {\csname\??constructionstophandler\currentconstructionhandler\endcsname} -% interactivity is handled in setup -% -% \unexpanded\setvalue{\??constructiontexthandler\v!btxlist}% -% {\begingroup -% \ifx\currentbtxnumbering\empty\else -% \startgoto[\s!internal(\currentbtxinternal)]% handled in setup -% \fi -% \directsetup{\v!btxrendering:\v!number:\constructionparameter\c!number}% -% \ifx\currentbtxnumbering\empty\else -% \stopgoto -% \fi -% \endgroup} -% -% so: +% interactivity is handled in setups \unexpanded\setvalue{\??constructiontexthandler\v!btxlist}% {\begingroup - \directsetup{\v!btxrendering:\v!number:\constructionparameter\c!number}% + \fastsetup{\v!btxrendering:\v!number:\constructionparameter\c!number}% \endgroup} % the whole entry can be interactive @@ -147,9 +135,7 @@ \relax \stopsetups -% todo: low level builder commands without using the constructor - -% construction +% construction (todo:low level builder commands without using the constructor) \unexpanded\def\strc_constructions_initialize#1% class instance {\edef\currentconstruction{#1}% @@ -221,7 +207,6 @@ \installcorenamespace {btxcitevariant} \installcorenamespace {btxrendering} \installcorenamespace {btxcommand} -%installcorenamespace {btxnumbering} \installcorenamespace {btxrenderingdefinition} \installcommandhandler \??btxdataset {btxdataset} \??btxdataset @@ -333,15 +318,14 @@ % \let\btxsetdataset\setbtxdataset % \let\btxsetentry \setbtxentry -\def\btxfield #1{\ctxcommand{btxfield("\currentbtxdataset","\currentbtxtag","#1")}} -\def\btxdetail #1{\ctxcommand{btxdetail("\currentbtxdataset","\currentbtxtag","#1")}} -\def\btxflush #1{\ctxcommand{btxflush("\currentbtxdataset","\currentbtxtag","#1")}} -%def\btxrendering#1{\ctxcommand{btxrendering("\currentbtxdataset","\currentbtxtag","#1","\btxrenderingparameter\c!interaction")}} -\def\btxdoifelse #1{\ctxcommand{btxdoifelse("\currentbtxdataset","\currentbtxtag","#1")}} -\def\btxdoif #1{\ctxcommand{btxdoif("\currentbtxdataset","\currentbtxtag","#1")}} -\def\btxdoifnot #1{\ctxcommand{btxdoifnot("\currentbtxdataset","\currentbtxtag","#1")}} +\def\btxfield #1{\ctxcommand{btxfield("\currentbtxdataset","\currentbtxtag","#1")}} +\def\btxdetail #1{\ctxcommand{btxdetail("\currentbtxdataset","\currentbtxtag","#1")}} +\def\btxflush #1{\ctxcommand{btxflush("\currentbtxdataset","\currentbtxtag","#1")}} +\def\btxdoifelse#1{\ctxcommand{btxdoifelse("\currentbtxdataset","\currentbtxtag","#1")}} +\def\btxdoif #1{\ctxcommand{btxdoif("\currentbtxdataset","\currentbtxtag","#1")}} +\def\btxdoifnot #1{\ctxcommand{btxdoifnot("\currentbtxdataset","\currentbtxtag","#1")}} -\let\btxsetup \directsetup +\let\btxsetup\fastsetup %D How complex will we go? Can we assume that e.g. an apa style will not be mixed %D with another one? I think this assumption is okay. For manuals we might want to @@ -361,7 +345,55 @@ \unexpanded\def\btxlbracket {\removeunwantedspaces\space[} \unexpanded\def\btxrbracket {\removeunwantedspaces]\space} -%D Rendering lists and citations. +%D Variables: + +\let\currentbtxbacklink \empty \unexpanded\def\btxsetbacklink {\def\currentbtxbacklink} +\let\currentbtxbacktrace \empty \unexpanded\def\btxsetbacktrace {\def\currentbtxbacktrace} +\let\currentbtxcategory \empty \unexpanded\def\btxsetcategory {\def\currentbtxcategory} +\let\currentbtxcombis \empty \unexpanded\def\btxsetcombis {\def\currentbtxcombis} +\let\currentbtxdataset \empty \unexpanded\def\btxsetdataset {\def\currentbtxdataset} +\let\currentbtxfirst \empty \unexpanded\def\btxsetfirst {\def\currentbtxfirst} +\let\currentbtxfirstnames \empty \unexpanded\def\btxsetfirstnames {\def\currentbtxfirstnames} +\let\currentbtxinitials \empty \unexpanded\def\btxsetinitials {\def\currentbtxinitials} +\let\currentbtxinternal \empty \unexpanded\def\btxsetinternal {\def\currentbtxinternal} +\let\currentbtxjuniors \empty \unexpanded\def\btxsetjuniors {\def\currentbtxjuniors} +\let\currentbtxlanguage \empty \unexpanded\def\btxsetlanguage {\def\currentbtxlanguage} +\let\currentbtxsecond \empty \unexpanded\def\btxsetsecond {\def\currentbtxsecond} +\let\currentbtxsurnames \empty \unexpanded\def\btxsetsurnames {\def\currentbtxsurnames} +\let\currentbtxtag \empty \unexpanded\def\btxsettag {\def\currentbtxtag} +\let\currentbtxvons \empty \unexpanded\def\btxsetvons {\def\currentbtxvons} +\let\currentbtxauthorvariant\v!normal \unexpanded\def\btxsetauthorvariant{\def\currentbtxauthorvariant} + +\newconstant\currentbtxoverflow \unexpanded\def\btxsetoverflow#1{\currentbtxoverflow#1\relax} +\newconstant\currentbtxconcat \unexpanded\def\btxsetconcat #1{\currentbtxconcat #1\relax} +\newconstant\currentbtxcount \unexpanded\def\btxsetcount #1{\currentbtxcount #1\relax} + +\def\currentbtxauthorvariant{normal} + +\unexpanded\def\btxlistreset + {\let\currentbtxcombis \empty + \let\currentbtxcategory \empty + \let\currentbtxinternal \empty + \let\currentbtxbacklink \empty + \let\currentbtxbacktrace\empty + \let\currentbtxlanguage \empty + \let\currentbtxtag \empty + \let\currentbtxdataset \empty} + +\unexpanded\def\btxcitereset % check for less .. not all resets needed + {\let \currentbtxfirst \empty + \let \currentbtxsecond \empty + \let \currentbtxinternal \empty + \let \currentbtxbacklink \empty + \let \currentbtxbacktrace\empty % not used here + \let \currentbtxlanguage \empty + \let \currentbtxdataset \empty + \let \currentbtxtag \empty + \setconstant\currentbtxoverflow \zerocount + \setconstant\currentbtxconcat \zerocount + \setconstant\currentbtxcount \zerocount} + +%D Tracing \newconditional\c_btx_trace @@ -370,6 +402,8 @@ {\settrue \c_btx_trace} {\setfalse\c_btx_trace} +%D Rendering lists and citations. + \unexpanded\def\startbtxrendering {\begingroup \dosingleempty\btx_start_rendering} @@ -396,7 +430,7 @@ %newdimen\d_publ_number_distance \ifdefined\btxblock \else \newcount\btxblock \fi \btxblock\plusone -\ifdefined\btxlistcounter \else \newcount\btxlistcounter \fi % maintaned here, maybe in lua too? +\ifdefined\btxlistcounter \else \newcount\btxlistcounter \fi % maintained here, maybe in lua too? \ifdefined\btxcitecounter \else \newcount\btxcitecounter \fi % maybe pass this to lua \newtoks \everysetupbtxlistplacement % name will change @@ -423,8 +457,6 @@ \fi \to \everydefinebtxrendering -\let\currentbtxcombis\empty % goes into the setups - \unexpanded\def\btx_entry_inject {\begingroup \edef\currentbtxcategory{\btxfield{category}}% @@ -436,7 +468,7 @@ \endgroup} \def\btx_entry_inject_yes - {\directsetup\currentbtxsetup + {\fastsetup\currentbtxsetup \removeunwantedspaces \ifx\currentbtxcombis\empty \else \btxrenderingparameter\c!separator @@ -450,7 +482,7 @@ {\begingroup \def\currentbtxtag{#1}% \ignorespaces - \directsetup{\s!btx:\currentbtxalternative:\currentbtxcategory}% + \fastsetup{\s!btx:\currentbtxalternative:\currentbtxcategory}% \removeunwantedspaces \endgroup} @@ -497,7 +529,7 @@ \def\publ_place_list_indeed {\startbtxrendering[\currentbtxrendering]% - % \directsetup{\btxrenderingparameter\c!setups}% specific initializations + % \fastsetup{\btxrenderingparameter\c!setups}% specific initializations % \determinelistcharacteristics[\currentbtxrendering]% \btx_set_rendering_alternative \edef\currentbtxdataset{\btxrenderingparameter\c!dataset}% @@ -540,36 +572,12 @@ \def\currentbtxblock{\number\btxblock} -\unexpanded\def\btxlistreset - {\let \currentbtxindex \!!zerocount % can be a constant - \let \currentbtxcombis \empty - \let \currentbtxcategory \empty - \let \currentbtxinternal \empty - \let \currentbtxbacklink \empty - \let \currentbtxbacktrace\empty - \let \currentbtxlanguage \empty - \let \currentbtxtag \empty - \let \currentbtxdataset \empty - %setconstant\currentbtxrealpage \zerocount - } - -\unexpanded\def\btxsetindex {\def\currentbtxindex} -\unexpanded\def\btxsetcombis {\def\currentbtxcombis} -\unexpanded\def\btxsetcategory {\def\currentbtxcategory} -\unexpanded\def\btxsetinternal {\def\currentbtxinternal} -\unexpanded\def\btxsetbacklink {\def\currentbtxbacklink} -\unexpanded\def\btxsetbacktrace{\def\currentbtxbacktrace} -%unexpanded\def\btxsetlanguage {\def\currentbtxlanguage} -\unexpanded\def\btxsettag {\def\currentbtxtag} - \unexpanded\def\btxsetlanguage#1% {\def\currentbtxlanguage{#1}% \ifx\currentbtxlanguage\currentlanguage \else \setcurrentlanguage\currentmainlanguage\currentbtxlanguage \fi} -\btxlistreset - % called at the lua end, for determining the width \unexpanded\def\btxchecklistentry @@ -592,7 +600,7 @@ \endgroup} \unexpanded\def\btxlistsetup#1% - {\directsetup{\s!btx:\s!list:#1}} + {\fastsetup{\s!btx:\s!list:#1}} \unexpanded\def\btx_reference_indeed {\begingroup @@ -664,13 +672,17 @@ \def\btx_flush_author_nop {\btx_flush_author{\btxlistvariantparameter\c!author}} \unexpanded\def\btx_flush_author#1#2% - {\edef\currentbtxfield{#2}% + {\begingroup + \edef\currentbtxfield{#2}% \let\currentbtxlistvariant\currentbtxfield \ctxcommand{btxauthor("\currentbtxdataset","\currentbtxtag","\currentbtxfield",{ combiner = "#1", + kind = "list", + % symbol = ".", etallimit = \number\btxlistvariantparameter\c!etallimit, etaldisplay = \number\btxlistvariantparameter\c!etaldisplay, - })}} + })}% + \endgroup} \unexpanded\def\btxflushauthorname {\btx_flush_author{name}} % #1 \unexpanded\def\btxflushauthornormal {\btx_flush_author{normal}} % #1 @@ -679,11 +691,31 @@ \unexpanded\def\btxflushauthorinvertedshort{\btx_flush_author{invertedshort}} % #1 \unexpanded\def\currentbtxciteauthor % always author - {\ctxcommand{btxauthor("\currentbtxdataset","\currentbtxtag","author",{ + {\begingroup + \ctxcommand{btxauthor("\currentbtxdataset","\currentbtxtag","author",{ combiner = "\btxcitevariantparameter\c!authorconversion", + kind = "cite", + % symbol = ".", etallimit = \number\btxcitevariantparameter\c!etallimit, etaldisplay = \number\btxcitevariantparameter\c!etaldisplay, - })}} + })}% + \endgroup} + +\unexpanded\def\btxstartauthor{\begingroup} +\unexpanded\def\btxstopauthor {\endgroup} + +\unexpanded\def\btxciteauthorsetup#1{\fastsetup{\s!btx:\s!cite:\s!author:#1}} +\unexpanded\def\btxlistauthorsetup#1{\fastsetup{\s!btx:\s!list:\s!author:#1}} + +% \btxflushauthor{author} +% \btxflushauthor{artauthor} +% \btxflushauthor{editor} +% +% \btxflushauthor[name]{author} +% \btxflushauthor[normal]{author} +% \btxflushauthor[normalshort]{author} +% \btxflushauthor[inverted]{author} +% \btxflushauthor[invertedshort]{author} % \btxflushauthor{author} % \btxflushauthor{artauthor} @@ -765,24 +797,6 @@ %D following (not user) command. We could tag without injecting a node but this way %D we also store the location, which makes it possible to ask local lists. -% all done at the lua end and using the nocite setup .. also tracing -% -% \unexpanded\def\btxdomarkcitation % called from lua end -% {\dontleavehmode -% \iftrialtypesetting -% \expandafter\gobblethreearguments -% \else -% \expandafter\publ_cite_mark_citation -% \fi} -% -% \def\publ_cite_mark_citation#1#2#3% called from lua end -% {\begingroup -% \edef\currentbtxdataset{#1}% -% \edef\currentbtxtag{#2}% -% \edef\currentbtxbacklink{#3}% -% \btxcitesetup\s!nocite -% \endgroup} - %D \macros{cite,nocite,citation,nocitation,usecitation} %D %D The inline \type {\cite} command creates a (often) short reference to a publication @@ -933,29 +947,8 @@ %D Cite helpers: -\newconstant\currentbtxconcat -\newconstant\currentbtxcount -%newconstant\currentbtxrealpage - -\unexpanded\def\btxcitereset - {\let \currentbtxfirst \empty - \let \currentbtxsecond \empty - \let \currentbtxinternal \empty - \let \currentbtxbacklink \empty - \let \currentbtxbacktrace\empty % not used here - \let \currentbtxlanguage \empty - \let \currentbtxdataset \empty - \let \currentbtxtag \empty - %setconstant\currentbtxrealpage \zerocount - \setconstant\currentbtxconcat \zerocount - \setconstant\currentbtxcount \zerocount} - -\btxcitereset - \unexpanded\def\btxcitesetup#1% - {%\btx_cite_reference_inject - \directsetup{btx:cite:#1}% - \btxcitereset} + {\fastsetup{\s!btx:\s!cite:#1}} % no \btxcitereset as we loose dataset and such \unexpanded\def\btxsetfirst {\def\currentbtxfirst} \unexpanded\def\btxsetsecond {\def\currentbtxsecond} @@ -965,22 +958,24 @@ \unexpanded\def\btxsetinternal {\def\currentbtxinternal} \unexpanded\def\btxsetcount #1{\setconstant\currentbtxcount #1\relax} \unexpanded\def\btxsetconcat #1{\setconstant\currentbtxconcat #1\relax} -%unexpanded\def\btxsetrealpage #1{\setconstant\currentbtxrealpage#1\relax} +\unexpanded\def\btxsetoverflow #1{\setconstant\currentbtxoverflow#1\relax} -\unexpanded\def\btxstartsubcite#1% - {\bgroup - \btxcitereset +\unexpanded\def\btxstartsubcite#1% #1 can go + {\begingroup + \btxcitereset % todo: limited set \def\currentbtxcitevariant{#1}% - \btxcitevariantparameter\c!left} + \btxcitevariantparameter\c!left + \relax} \unexpanded\def\btxstopsubcite - {\btxcitevariantparameter\c!right - \egroup} - -%D List helpers: + {\relax + \btxcitevariantparameter\c!right + \endgroup} -\let\currentbtxindex \!!zerocount -\let\currentbtxcategory\empty +\let\btxstartcite \begingroup +\let\btxstopcite \endgroup +\let\btxstartciteauthor\begingroup +\let\btxstopciteauthor \endgroup %D Whatever helpers: @@ -1201,17 +1196,34 @@ [artauthor] [author] +% Not that efficient but ... + \setupbtxcitevariant - [\c!authorconversion=name, % \btxlistvariantparameter\c!authorconversion, - \c!etallimit =\btxlistvariantparameter\c!etallimit, - \c!etaldisplay =\btxlistvariantparameter\c!etaldisplay] + [\c!namesep=\btxlistvariantparameter\c!namesep, + \c!lastnamesep=\btxlistvariantparameter\c!lastnamesep, + \c!finalnamesep=\btxlistvariantparameter\c!finalnamesep, + \c!firstnamesep=\btxlistvariantparameter\c!firstnamesep, + \c!juniorsep=\btxlistvariantparameter\c!juniorsep, + \c!vonsep=\btxlistvariantparameter\c!vonsep, + \c!initialsep=\btxlistvariantparameter\c!initialsep, + \c!surnamesep=\btxlistvariantparameter\c!surnamesep, + \c!surnameinitialsep=\btxlistvariantparameter\c!surnameinitialsep, + \c!surnamefirstnamesep=\btxlistvariantparameter\c!surnamefirstnamesep, + \c!etallimit=\btxlistvariantparameter\c!etallimit, + \c!etaldisplay=\btxlistvariantparameter\c!etaldisplay, + \c!etaltext=\btxlistvariantparameter\c!etaltext, + \c!monthconversion=\btxlistvariantparameter\c!monthconversion, + \c!authorconversion=\v!name] % Do we want these in the format? Loading them delayed is somewhat messy. -\loadbtxdefinitionfile[apa] -\loadbtxdefinitionfile[cite] -\loadbtxdefinitionfile[list] \loadbtxdefinitionfile[commands] \loadbtxdefinitionfile[definitions] +\loadbtxdefinitionfile[cite] +\loadbtxdefinitionfile[list] +\loadbtxdefinitionfile[author] + +\loadbtxdefinitionfile[apa] + \protect diff --git a/tex/context/base/status-files.pdf b/tex/context/base/status-files.pdf Binary files differindex 8eee56299..95da7c75e 100644 --- a/tex/context/base/status-files.pdf +++ b/tex/context/base/status-files.pdf diff --git a/tex/context/base/status-lua.pdf b/tex/context/base/status-lua.pdf Binary files differindex 7541cdaba..b095cf6bc 100644 --- a/tex/context/base/status-lua.pdf +++ b/tex/context/base/status-lua.pdf diff --git a/tex/context/base/strc-con.mkvi b/tex/context/base/strc-con.mkvi index 1862b00a6..b04f9231d 100644 --- a/tex/context/base/strc-con.mkvi +++ b/tex/context/base/strc-con.mkvi @@ -352,10 +352,6 @@ \ifx\p_strc_constructions_align\empty \else \setupalign[\p_strc_constructions_align]% \use... \fi - \edef\p_strc_constructions_indenting{\constructionparameter\c!indenting}% - \ifx\p_strc_constructions_indenting\empty \else - \indenting[\p_strc_constructions_indenting]% \use... - \fi \ifcase\c_strc_constructions_nested_state \c_strc_constructions_nested_state\plusone \or @@ -366,6 +362,11 @@ \edef\p_strc_constructions_headalign{\constructionparameter\c!headalign}% % \directsetup\p_strc_constructions_renderingsetup\relax + % moved to here 2014-07-03 + \edef\p_strc_constructions_indenting{\constructionparameter\c!indenting}% + \ifx\p_strc_constructions_indenting\empty \else + \indenting[\p_strc_constructions_indenting]% \use... + \fi % \dostoptagged % tag \dostarttagged\t!constructioncontent\empty diff --git a/tex/context/base/strc-reg.lua b/tex/context/base/strc-reg.lua index e9186e390..da4ba9b2d 100644 --- a/tex/context/base/strc-reg.lua +++ b/tex/context/base/strc-reg.lua @@ -64,6 +64,10 @@ local a_destination = attributes.private('destination') local absmaxlevel = 5 -- \c_strc_registers_maxlevel +local h_prefixpage = helpers.prefixpage +local h_prefixlastpage = helpers.prefixlastpage +local h_title = helpers.title + local ctx_startregisteroutput = context.startregisteroutput local ctx_stopregisteroutput = context.stopregisteroutput local ctx_startregistersection = context.startregistersection @@ -74,13 +78,115 @@ local ctx_startregisterentry = context.startregisterentry local ctx_stopregisterentry = context.stopregisterentry local ctx_startregisterpages = context.startregisterpages local ctx_stopregisterpages = context.stopregisterpages -local ctx_stopregisterseewords = context.stopregisterseewords local ctx_startregisterseewords = context.startregisterseewords +local ctx_stopregisterseewords = context.stopregisterseewords local ctx_registerentry = context.registerentry local ctx_registerseeword = context.registerseeword local ctx_registerpagerange = context.registerpagerange local ctx_registeronepage = context.registeronepage +-- possible export, but ugly code (overloads) +-- +-- local output, section, entries, nofentries, pages, words, rawtext +-- +-- h_title = function(a,b) rawtext = a end +-- +-- local function ctx_startregisteroutput() +-- output = { } +-- section = nil +-- entries = nil +-- nofentries = nil +-- pages = nil +-- words = nil +-- rawtext = nil +-- end +-- local function ctx_stopregisteroutput() +-- inspect(output) +-- output = nil +-- section = nil +-- entries = nil +-- nofentries = nil +-- pages = nil +-- words = nil +-- rawtext = nil +-- end +-- local function ctx_startregistersection(tag) +-- section = { } +-- output[#output+1] = { +-- section = section, +-- tag = tag, +-- } +-- end +-- local function ctx_stopregistersection() +-- end +-- local function ctx_startregisterentries(n) +-- entries = { } +-- nofentries = 0 +-- section[#section+1] = entries +-- end +-- local function ctx_stopregisterentries() +-- end +-- local function ctx_startregisterentry(n) -- or subentries (nested?) +-- nofentries = nofentries + 1 +-- entry = { } +-- entries[nofentries] = entry +-- end +-- local function ctx_stopregisterentry() +-- nofentries = nofentries - 1 +-- entry = entries[nofentries] +-- end +-- local function ctx_startregisterpages() +-- pages = { } +-- entry.pages = pages +-- end +-- local function ctx_stopregisterpages() +-- end +-- local function ctx_startregisterseewords() +-- words = { } +-- entry.words = words +-- end +-- local function ctx_stopregisterseewords() +-- end +-- local function ctx_registerentry(processor,internal,seeparent,text) +-- text() +-- entry.text = { +-- processor = processor, +-- internal = internal, +-- seeparent = seeparent, +-- text = rawtext, +-- } +-- end +-- local function ctx_registerseeword(i,n,processor,internal,seeindex,seetext) +-- seetext() +-- entry.words[i] = { +-- processor = processor, +-- internal = internal, +-- seeparent = seeparent, +-- seetext = rawtext, +-- } +-- end +-- local function ctx_registerpagerange(fprocessor,finternal,frealpage,lprocessor,linternal,lrealpage) +-- pages[#pages+1] = { +-- first = { +-- processor = fprocessor, +-- internal = finternal, +-- realpage = frealpage, +-- }, +-- last = { +-- processor = lprocessor, +-- internal = linternal, +-- realpage = lrealpage, +-- }, +-- } +-- end +-- local function ctx_registeronepage(processor,internal,realpage) +-- pages[#pages+1] = { +-- processor = processor, +-- internal = internal, +-- realpage = realpage, +-- } +-- end + -- some day we will share registers and lists (although there are some conceptual -- differences in the application of keywords) @@ -716,7 +822,6 @@ function registers.analyze(class,options) context(analyzeregister(class,options)) end - -- todo take conversion from index function registers.userdata(index,name) @@ -734,10 +839,6 @@ end -- todo: ownnumber -local h_prefixpage = helpers.prefixpage -local h_prefixlastpage = helpers.prefixlastpage -local h_title = helpers.title - local function pagerange(f_entry,t_entry,is_last,prefixspec,pagespec) local fer, ter = f_entry.references, t_entry.references ctx_registerpagerange( @@ -1063,7 +1164,8 @@ function registers.flush(data,options,prefixspec,pagespec) local seetext = seeword.text or "" local processor = seeword.processor or (entry.processors and entry.processors[1]) or "" local seeindex = entry.references.seeindex or "" - ctx_registerseeword(i,n,processor,0,seeindex,seetext) + -- ctx_registerseeword(i,nt,processor,0,seeindex,seetext) + ctx_registerseeword(i,nt,processor,0,seeindex,function() h_title(seetext,metadata) end) end ctx_stopregisterseewords() end diff --git a/tex/context/base/util-env.lua b/tex/context/base/util-env.lua index e96a464b0..b72226900 100644 --- a/tex/context/base/util-env.lua +++ b/tex/context/base/util-env.lua @@ -9,11 +9,11 @@ if not modules then modules = { } end modules ['util-env'] = { local allocate, mark = utilities.storage.allocate, utilities.storage.mark local format, sub, match, gsub, find = string.format, string.sub, string.match, string.gsub, string.find -local unquoted, quoted = string.unquoted, string.quoted +local unquoted, quoted, optionalquoted = string.unquoted, string.quoted, string.optionalquoted local concat, insert, remove = table.concat, table.insert, table.remove -environment = environment or { } -local environment = environment +environment = environment or { } +local environment = environment -- precautions @@ -182,26 +182,14 @@ function environment.splitarguments(separator) -- rather special, cut-off before end function environment.reconstructcommandline(arg,noquote) + local resolveprefix = resolvers.resolve -- something rather special arg = arg or environment.originalarguments if noquote and #arg == 1 then - -- we could just do: return unquoted(resolvers.resolve(arg[i])) - local a = arg[1] - a = resolvers.resolve(a) - a = unquoted(a) - return a + return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1]) elseif #arg > 0 then local result = { } for i=1,#arg do - -- we could just do: result[#result+1] = format("%q",unquoted(resolvers.resolve(arg[i]))) - local a = arg[i] - a = resolvers.resolve(a) - a = unquoted(a) - a = gsub(a,'"','\\"') -- tricky - if find(a," ",1,true) then - result[#result+1] = quoted(a) - else - result[#result+1] = a - end + result[i] = optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix) end return concat(result," ") else @@ -238,26 +226,10 @@ end -- print(environment.relativepath("//x")) -- //x -- print(environment.relativepath()) -- e:/tmp --- -- to be tested: --- --- function environment.reconstructcommandline(arg,noquote) --- arg = arg or environment.originalarguments --- if noquote and #arg == 1 then --- return unquoted(resolvers.resolve(arg[1])) --- elseif #arg > 0 then --- local result = { } --- for i=1,#arg do --- result[#result+1] = format("%q",unquoted(resolvers.resolve(arg[i]))) -- always quote --- end --- return concat(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 diff --git a/tex/context/base/util-str.lua b/tex/context/base/util-str.lua index 89d8bb48d..2739a20c4 100644 --- a/tex/context/base/util-str.lua +++ b/tex/context/base/util-str.lua @@ -1094,3 +1094,23 @@ end -- string.formatteds = formatteds -- -- setmetatable(formatteds, { __index = make, __call = use }) + +-- This is a somewhat silly one used in commandline reconstruction but the older +-- method, using a combination of fine, gsub, quoted and unquoted was not that +-- reliable. +-- +-- '"foo"bar \"and " whatever"' => "foo\"bar \"and \" whatever" +-- 'foo"bar \"and " whatever' => "foo\"bar \"and \" whatever" + +local dquote = patterns.dquote -- P('"') +local equote = patterns.escaped + dquote / '\\"' + 1 +local space = patterns.space +local cquote = Cc('"') + +local pattern = + Cs(dquote * (equote - P(-2))^0 * dquote) -- we keep the outer but escape unescaped ones + + Cs(cquote * (equote - space)^0 * space * equote^0 * cquote) -- we escape unescaped ones + +function string.optionalquoted(str) + return lpegmatch(pattern,str) or str +end diff --git a/tex/context/test/pdf-a1b-2005.mkiv b/tex/context/test/pdf-a1b-2005.mkiv index f980e3148..bc970c3f9 100644 --- a/tex/context/test/pdf-a1b-2005.mkiv +++ b/tex/context/test/pdf-a1b-2005.mkiv @@ -1,9 +1,9 @@ % PDF/A-1b:2005 -\enabletrackers[structure.tags,backend.tags] +\enabletrackers[structure.tags,backend.tags,backend.xmp] \setupbackend - [format=PDF/A-1a:2005, + [format=PDF/A-1b:2005, intent=sRGB IEC61966-2.1, % use <info> entry here; otherwise problems with predefined default profile profile=sRGB.icc, % use <filename> here level=0] @@ -20,8 +20,6 @@ Text is needed, otherwise tagging base entries are not applied. -\stopchapter - \stoptextcolor %\startTEXpage diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index 5f509be8a..a62958c1c 100644 --- a/tex/generic/context/luatex/luatex-fonts-merged.lua +++ b/tex/generic/context/luatex/luatex-fonts-merged.lua @@ -1,6 +1,6 @@ -- merged file : luatex-fonts-merged.lua -- parent file : luatex-fonts.lua --- merge date : 06/27/14 10:53:59 +-- merge date : 07/03/14 14:52:08 do -- begin closure to overcome local limits and interference @@ -978,14 +978,14 @@ local function sortedhash(t,cmp) end local n=0 local m=#s - local function kv(s) + local function kv() if n<m then n=n+1 local k=s[n] return k,t[k] end end - return kv,s + return kv else return nothing end @@ -1746,6 +1746,44 @@ function table.values(t,s) return {} end end +function table.filtered(t,pattern,sort,cmp) + if t and type(pattern)=="string" then + if sort then + local s + if cmp then + s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) + else + s=sortedkeys(t) + end + local n=0 + local m=#s + local function kv(s) + while n<m do + n=n+1 + local k=s[n] + if find(k,pattern) then + return k,t[k] + end + end + end + return kv,s + else + local n=next(t) + local function iterator() + while n do + local k=n + n=next(t,k) + if find(k,pattern) then + return k,t[k] + end + end + end + return iterator,t + end + else + return nothing + end +end end -- closure @@ -3211,6 +3249,15 @@ else add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=lpeg.patterns.texescape }) add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=lpeg.patterns.luaescape }) end +local dquote=patterns.dquote +local equote=patterns.escaped+dquote/'\\"'+1 +local space=patterns.space +local cquote=Cc('"') +local pattern=Cs(dquote*(equote-P(-2))^0*dquote) ++Cs(cquote*(equote-space)^0*space*equote^0*cquote) +function string.optionalquoted(str) + return lpegmatch(pattern,str) or str +end end -- closure @@ -6617,7 +6664,7 @@ local report_otf=logs.reporter("fonts","otf loading") local fonts=fonts local otf=fonts.handlers.otf otf.glists={ "gsub","gpos" } -otf.version=2.755 +otf.version=2.756 otf.cache=containers.define("fonts","otf",otf.version,true) local fontdata=fonts.hashes.identifiers local chardata=characters and characters.data @@ -7821,6 +7868,14 @@ actions["reorganize lookups"]=function(data,filename,raw) rule.current=s_hashed(names,s_h_cache) end rule.glyphs=nil + local lookups=rule.lookups + if lookups then + for i=1,#names do + if not lookups[i] then + lookups[i]="" + end + end + end end end end |