1if not modules then modules = { } end modules ['file-job'] = {
2 version = 1.001,
3 comment = "companion to file-job.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9
10
11
12local next, rawget, tostring, tonumber = next, rawget, tostring, tonumber
13local gsub, match, gmatch, ind = string.gsub, string.match, string.gmatch, string.find
14local insert, remove, concat = table.insert, table.remove, table.concat
15local validstring, formatters = string.valid, string.formatters
16local sortedhash = table.sortedhash
17local setmetatableindex, setmetatablenewindex = table.setmetatableindex, table.setmetatablenewindex
18
19local commands = commands
20local resolvers = resolvers
21local context = context
22
23local ctx_doifelse = commands.doifelse
24
25local implement = interfaces.implement
26
27local trace_jobfiles = false trackers.register("system.jobfiles", function(v) trace_jobfiles = v end)
28
29local report = logs.reporter("system")
30local report_jobfiles = logs.reporter("system", "jobfiles")
31local report_functions = logs.reporter("system", "functions")
32
33local texsetcount = tex.setcount
34local elements = interfaces.elements
35local constants = interfaces.constants
36local variables = interfaces.variables
37local settings_to_array = utilities.parsers.settings_to_array
38local allocate = utilities.storage.allocate
39
40local nameonly = file.nameonly
41local suffixonly = file.suffix
42local basename = file.basename
43local addsuffix = file.addsuffix
44local removesuffix = file.removesuffix
45local dirname = file.dirname
46local is_qualified_path = file.is_qualified_path
47
48local cleanpath = resolvers.cleanpath
49local toppath = resolvers.toppath
50local resolveprefix = resolvers.resolve
51
52local currentfile = luatex.currentfile
53
54local hasscheme = url.hasscheme
55
56local jobresolvers = resolvers.jobs
57
58local registerextrapath = resolvers.registerextrapath
59local resetextrapaths = resolvers.resetextrapaths
60local getextrapaths = resolvers.getextrapath
61local pushextrapath = resolvers.pushextrapath
62local popextrapath = resolvers.popextrapath
63
64
65local v_text = variables.text
66local v_project = variables.project
67local v_environment = variables.environment
68local v_product = variables.product
69local v_component = variables.component
70local v_yes = variables.yes
71
72
73
74local function findctxfile(name)
75 if is_qualified_path(name) then
76 return name
77 elseif not hasscheme(name) then
78 return resolvers.finders.byscheme("loc",name) or ""
79 else
80 return resolvers.findtexfile(name) or ""
81 end
82end
83
84resolvers.findctxfile = findctxfile
85
86implement {
87 name = "processfile",
88 arguments = "string",
89 public = true,
90 protected = true,
91 actions = function(name)
92 name = findctxfile(name)
93 if name ~= "" then
94 context.input(name)
95 end
96 end
97}
98
99implement {
100 name = "doifelseinputfile",
101 arguments = "string",
102 public = true,
103 protected = true,
104 actions = function(name)
105 ctx_doifelse(findctxfile(name) ~= "")
106 end
107}
108
109implement {
110 name = "locatefilepath",
111 arguments = "string",
112 actions = function(name)
113 context(dirname(findctxfile(name)))
114 end
115}
116
117implement {
118 name = "usepath",
119 arguments = "optional",
120 public = true,
121 protected = true,
122 actions = function(paths)
123 report_jobfiles("using path: %s",paths)
124 registerextrapath(paths)
125 end
126}
127
128implement {
129 name = "pushpath",
130 arguments = "optional",
131 public = true,
132 protected = true,
133 actions = function(paths)
134 report_jobfiles("pushing path: %s",paths)
135 pushextrapath(paths)
136 end
137}
138
139implement {
140 name = "poppath",
141 public = true,
142 protected = true,
143 actions = function(paths)
144 popextrapath()
145 report_jobfiles("popping path")
146 end
147}
148
149implement {
150 name = "usesubpath",
151 arguments = "optional",
152 public = true,
153 protected = true,
154 actions = function(subpaths)
155 report_jobfiles("using subpath: %s",subpaths)
156 registerextrapath(nil,subpaths)
157 end
158}
159
160implement {
161 name = "resetpath",
162 public = true,
163 protected = true,
164 actions = function()
165 report_jobfiles("resetting path")
166 resetextrapaths()
167 end
168}
169
170implement {
171 name = "allinputpaths",
172 public = true,
173 actions = function()
174 context(concat(getextrapaths(),","))
175 end
176}
177
178implement {
179 name = "usezipfile",
180 public = true,
181 protected = true,
182 arguments = { "optional", "optional" },
183 actions = function(name,tree)
184 if tree and tree ~= "" then
185 resolvers.usezipfile(formatters["zip:///%s?tree=%s"](name,tree))
186 else
187 resolvers.usezipfile(formatters["zip:///%s"](name))
188 end
189 end
190}
191
192
193
194local texpatterns = { "%s.mklx", "%s.mkxl", "%s.mkvi", "%s.mkiv", "%s.tex" }
195local luapatterns = { "%s" .. utilities.lua.suffixes.luc, "%s.lua", "%s.lmt" }
196local cldpatterns = { "%s.cld" }
197local xmlpatterns = { "%s.xml" }
198
199local uselibrary = resolvers.uselibrary
200local input = context.input
201
202
203
204
205
206local processstack = { }
207local processedfile = ""
208local processedfiles = { }
209
210implement {
211 name = "processedfile",
212 actions = function()
213 context(processedfile)
214 end
215}
216
217implement {
218 name = "processedfiles",
219 actions = function()
220 context(concat(processedfiles,","))
221 end
222}
223
224implement {
225 name = "dostarttextfile",
226 public = true,
227 protected = true,
228 arguments = "string",
229 actions = function(name)
230 insert(processstack,name)
231 processedfile = name
232 insert(processedfiles,name)
233 end
234}
235
236implement {
237 name = "dostoptextfile",
238 public = true,
239 protected = true,
240 actions = function()
241 processedfile = remove(processstack) or ""
242 end
243}
244
245local function startprocessing(name,notext)
246 if not notext then
247
248 context.dostarttextfile(name)
249 end
250end
251
252local function stopprocessing(notext)
253 if not notext then
254 context.dostoptextfile()
255
256 end
257end
258
259
260
261local typestack = { }
262local currenttype = v_text
263local nofmissing = 0
264local missing = {
265 tex = setmetatableindex("number"),
266 lua = setmetatableindex("number"),
267 cld = setmetatableindex("number"),
268 xml = setmetatableindex("number"),
269}
270
271local function reportfailure(kind,name)
272 nofmissing = nofmissing + 1
273 missing[kind][name] = true
274 report_jobfiles("unknown %s file %a",kind,name)
275end
276
277
278
279local function action(name,foundname)
280 input(foundname)
281end
282local function failure(name,foundname)
283 reportfailure("tex",name)
284end
285local function usetexfile(name,onlyonce,notext)
286 startprocessing(name,notext)
287 uselibrary {
288 name = name,
289 patterns = texpatterns,
290 action = action,
291 failure = failure,
292 onlyonce = onlyonce,
293 }
294 stopprocessing(notext)
295end
296
297local function action(name,foundname)
298 dofile(foundname)
299end
300local function failure(name,foundname)
301 reportfailure("lua",name)
302end
303local function useluafile(name,onlyonce,notext)
304 uselibrary {
305 name = name,
306 patterns = luapatterns,
307 action = action,
308 failure = failure,
309 onlyonce = onlyonce,
310 }
311end
312
313local function action(name,foundname)
314 dofile(foundname)
315end
316local function failure(name,foundname)
317 reportfailure("cld",name)
318end
319local function usecldfile(name,onlyonce,notext)
320 startprocessing(name,notext)
321 uselibrary {
322 name = name,
323 patterns = cldpatterns,
324 action = action,
325 failure = failure,
326 onlyonce = onlyonce,
327 }
328 stopprocessing(notext)
329end
330
331local function action(name,foundname)
332 context.xmlprocess(foundname,"main","")
333end
334local function failure(name,foundname)
335 reportfailure("xml",name)
336end
337local function usexmlfile(name,onlyonce,notext)
338 startprocessing(name,notext)
339 uselibrary {
340 name = name,
341 patterns = xmlpatterns,
342 action = action,
343 failure = failure,
344 onlyonce = onlyonce,
345 }
346 stopprocessing(notext)
347end
348
349local suffixes = {
350 mkvi = usetexfile,
351 mkiv = usetexfile,
352 mklx = usetexfile,
353 mkxl = usetexfile,
354 tex = usetexfile,
355 luc = useluafile,
356 lua = useluafile,
357 cld = usecldfile,
358 xml = usexmlfile,
359 [""] = usetexfile,
360}
361
362local function useanyfile(name,onlyonce)
363 local s = suffixes[suffixonly(name)]
364 context(function() resolvers.pushpath(name) end)
365 if s then
366
367 s(name,onlyonce)
368 else
369 usetexfile(name,onlyonce)
370
371 end
372 context(resolvers.poppath)
373end
374
375implement { name = "loadtexfile", public = true, protected = true, actions = usetexfile, arguments = "optional" }
376implement { name = "loadluafile", public = true, protected = true, actions = useluafile, arguments = "optional" }
377implement { name = "loadcldfile", public = true, protected = true, actions = usecldfile, arguments = "optional" }
378implement { name = "loadxmlfile", public = true, protected = true, actions = usexmlfile, arguments = "optional" }
379
380implement { name = "loadtexfileonce", public = true, protected = true, actions = usetexfile, arguments = { "optional", true } }
381implement { name = "loadluafileonce", public = true, protected = true, actions = useluafile, arguments = { "optional", true } }
382implement { name = "loadcldfileonce", public = true, protected = true, actions = usecldfile, arguments = { "optional", true } }
383implement { name = "loadxmlfileonce", public = true, protected = true, actions = usexmlfile, arguments = { "optional", true } }
384
385implement { name = "useanyfile", actions = useanyfile, arguments = "string" }
386implement { name = "useanyfileonce", actions = useanyfile, arguments = { "string", true } }
387
388function jobresolvers.usefile(name,onlyonce,notext)
389 local s = suffixes[suffixonly(name)]
390 if s then
391
392 s(name,onlyonce,notext)
393 end
394end
395
396
397
398local textlevel = 0
399
400local function dummyfunction() end
401
402local function startstoperror()
403 report("invalid \\%s%s ... \\%s%s structure",elements.start,v_text,elements.stop,v_text)
404 startstoperror = dummyfunction
405end
406
407local stopped
408
409local function starttext()
410 if textlevel == 0 then
411 if trace_jobfiles then
412 report_jobfiles("starting text")
413 end
414 context.dostarttext()
415 end
416 textlevel = textlevel + 1
417 texsetcount("global","textlevel",textlevel)
418end
419
420local function stoptext()
421 if not stopped then
422 if textlevel == 0 then
423 startstoperror()
424 elseif textlevel > 0 then
425 textlevel = textlevel - 1
426 end
427 texsetcount("global","textlevel",textlevel)
428 if textlevel <= 0 then
429 if trace_jobfiles then
430 report_jobfiles("stopping text")
431 end
432 context.dostoptext()
433 stopped = true
434 end
435 end
436end
437
438implement {
439 name = "starttext",
440 public = true,
441 protected = true,
442 actions = starttext
443}
444
445implement {
446 name = "stoptext",
447 public = true,
448 protected = true,
449 actions = stoptext
450}
451
452implement {
453 name = "forcequitjob",
454 arguments = "string",
455 public = true,
456 protected = true,
457 actions = function(reason)
458 if reason then
459 report("forcing quit: %s",reason)
460 else
461 report("forcing quit")
462 end
463 context.batchmode()
464 while textlevel >= 0 do
465 context.stoptext()
466 end
467 end
468}
469
470implement {
471 name = "forceendjob",
472 public = true,
473 protected = true,
474 actions = function()
475 report([[don't use \end to finish a document]])
476 context.stoptext()
477 end
478}
479
480implement {
481 name = "autostarttext",
482 public = true,
483 protected = true,
484 actions = function()
485 if textlevel == 0 then
486 report([[auto \starttext ... \stoptext]])
487 end
488 context.starttext()
489 end
490}
491
492implement {
493 name = "autostoptext",
494 public = true,
495 protected = true,
496 actions = stoptext
497}
498
499
500
501implement {
502 name = "processfilemany",
503 public = true,
504 protected = true,
505 arguments = { "string", false },
506 actions = useanyfile
507}
508
509implement {
510 name = "processfileonce",
511 public = true,
512 protected = true,
513 arguments = { "string", true },
514 actions = useanyfile
515}
516
517implement {
518 name = "processfilenone",
519 arguments = "string",
520 public = true,
521 protected = true,
522 actions = dummyfunction,
523}
524
525local tree = { type = "text", name = "", branches = { } }
526local treestack = { }
527local top = tree.branches
528local root = tree
529
530local project_stack = { }
531local product_stack = { }
532local component_stack = { }
533local environment_stack = { }
534
535local stacks = {
536 [v_project ] = project_stack,
537 [v_product ] = product_stack,
538 [v_component ] = component_stack,
539 [v_environment] = environment_stack,
540}
541
542
543
544local function pushtree(what,name)
545 local t = { }
546 top[#top+1] = { type = what, name = name, branches = t }
547 insert(treestack,top)
548 top = t
549end
550
551local function poptree()
552 top = remove(treestack)
553 if #top[#top].branches == 0 then
554 top[#top].branches = nil
555 end
556end
557
558do
559
560 local function log_tree(report,top,depth)
561 report("%s%s: %s",depth,top.type,top.name)
562 local branches = top.branches
563 if branches then
564 local n = #branches
565 if n > 0 then
566 depth = depth .. " "
567 for i=1,n do
568 log_tree(report,branches[i],depth)
569 end
570 else
571 top.brances = nil
572 end
573 end
574 end
575
576 logs.registerfinalactions(function()
577 root.name = environment.jobname
578
579 logs.startfilelogging(report,"used files")
580 log_tree(report,root,"")
581 logs.stopfilelogging()
582
583 if nofmissing > 0 and logs.loggingerrors() then
584 logs.starterrorlogging(report,"missing files")
585 for kind, list in sortedhash(missing) do
586 for name in sortedhash(list) do
587 report("%w%s %s",6,kind,name)
588 end
589 end
590 logs.stoperrorlogging()
591 end
592 end)
593
594end
595
596local jobstructure = job.structure or { }
597job.structure = jobstructure
598jobstructure.collected = jobstructure.collected or { }
599jobstructure.tobesaved = root
600jobstructure.components = { }
601
602local function initialize()
603 local function collect(root,result)
604 local branches = root.branches
605 if branches then
606 for i=1,#branches do
607 local branch = branches[i]
608 if branch.type == "component" then
609 result[#result+1] = branch.name
610 end
611 collect(branch,result)
612 end
613 end
614 return result
615 end
616 jobstructure.components = collect(jobstructure.collected,{})
617end
618
619job.register('job.structure.collected',root,initialize)
620
621
622
623
624local ctx_processfilemany = context.processfilemany
625local ctx_processfileonce = context.processfileonce
626local ctx_processfilenone = context.processfilenone
627
628
629
630local function processfilecommon(name,action)
631
632
633
634
635
636
637
638
639
640 action(name)
641end
642
643local function processfilemany(name) processfilecommon(name,ctx_processfilemany) end
644local function processfileonce(name) processfilecommon(name,ctx_processfileonce) end
645local function processfilenone(name) processfilecommon(name,ctx_processfilenone) end
646
647local processors = utilities.storage.allocate {
648
649
650
651
652
653
654
655 [v_text] = {
656 [v_text] = { "many", processfilemany },
657 [v_project] = { "once", processfileonce },
658 [v_environment] = { "once", processfileonce },
659 [v_product] = { "many", processfilemany },
660 [v_component] = { "many", processfilemany },
661 },
662 [v_project] = {
663 [v_text] = { "many", processfilemany },
664 [v_project] = { "none", processfilenone },
665 [v_environment] = { "once", processfileonce },
666 [v_product] = { "none", processfilenone },
667 [v_component] = { "none", processfilenone },
668 },
669 [v_environment] = {
670 [v_text] = { "many", processfilemany },
671 [v_project] = { "none", processfilenone },
672 [v_environment] = { "once", processfileonce },
673 [v_product] = { "none", processfilenone },
674 [v_component] = { "none", processfilenone },
675 },
676 [v_product] = {
677 [v_text] = { "many", processfilemany },
678 [v_project] = { "once", processfileonce },
679 [v_environment] = { "once", processfileonce },
680 [v_product] = { "many", processfilemany },
681 [v_component] = { "many", processfilemany },
682 },
683 [v_component] = {
684 [v_text] = { "many", processfilemany },
685 [v_project] = { "once", processfileonce },
686 [v_environment] = { "once", processfileonce },
687 [v_product] = { "none", processfilenone },
688 [v_component] = { "many", processfilemany },
689 }
690}
691
692local start = {
693 [v_text] = nil,
694 [v_project] = nil,
695 [v_environment] = context.startreadingfile,
696 [v_product] = context.starttext,
697 [v_component] = context.starttext,
698}
699
700local stop = {
701 [v_text] = nil,
702 [v_project] = nil,
703 [v_environment] = context.stopreadingfile,
704 [v_product] = context.stoptext,
705 [v_component] = context.stoptext,
706}
707
708jobresolvers.processors = processors
709
710local function topofstack(what)
711 local stack = stacks[what]
712 return stack and stack[#stack] or environment.jobname
713end
714
715local function productcomponent()
716 local product = product_stack[#product_stack]
717 if product and product ~= "" then
718 local component = component_stack[1]
719 if component and component ~= "" then
720 return component
721 end
722 end
723end
724
725local function justacomponent()
726 local product = product_stack[#product_stack]
727 if not product or product == "" then
728 local component = component_stack[1]
729 if component and component ~= "" then
730 return component
731 end
732 end
733end
734
735jobresolvers.productcomponent = productcomponent
736jobresolvers.justacomponent = justacomponent
737
738function jobresolvers.currentproject () return topofstack(v_project ) end
739function jobresolvers.currentproduct () return topofstack(v_product ) end
740function jobresolvers.currentcomponent () return topofstack(v_component ) end
741function jobresolvers.currentenvironment() return topofstack(v_environment) end
742
743local done = { }
744local tolerant = false
745
746local function process(what,name)
747 local depth = #typestack
748 local process
749
750 name = resolveprefix(name)
751
752
753
754 process = processors[currenttype][what]
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770 if process then
771 local method = process[1]
772 if method == "none" then
773 if trace_jobfiles then
774 report_jobfiles("%s : %s : %s %s %a in %s %a",depth,method,"ignoring",what,name,currenttype,topofstack(currenttype))
775 end
776 elseif method == "once" and done[name] then
777 if trace_jobfiles then
778 report_jobfiles("%s : %s : %s %s %a in %s %a",depth,method,"skipping",what,name,currenttype,topofstack(currenttype))
779 end
780 else
781
782
783 done[name] = true
784 local before = start[what]
785 local after = stop [what]
786 if trace_jobfiles then
787 report_jobfiles("%s : %s : %s %s %a in %s %a",depth,method,"processing",what,name,currenttype,topofstack(currenttype))
788 end
789 if before then
790 before()
791 end
792 process[2](name)
793 if after then
794 after()
795 end
796 end
797 else
798 if trace_jobfiles then
799 report_jobfiles("%s : %s : %s %s %a in %s %a",depth,"none","ignoring",what,name,currenttype,topofstack(currenttype))
800 end
801 end
802end
803
804local scan_delimited = tokens.scanners.delimited
805
806local function getname()
807 return scan_delimited(91,93) or scan_delimited(0,32)
808end
809
810implement { name = "project", public = true, protected = true, actions = function() process(v_project, getname()) end }
811implement { name = "environment", public = true, protected = true, actions = function() process(v_environment,getname()) end }
812implement { name = "product", public = true, protected = true, actions = function() process(v_product, getname()) end }
813implement { name = "component", public = true, protected = true, actions = function() process(v_component, getname()) end }
814
815implement { name = "useproject", public = true, protected = true, actions = function(name) process(v_project, name) end, arguments = "optional" }
816implement { name = "useenvironment", public = true, protected = true, actions = function(name) process(v_environment,name) end, arguments = "optional" }
817implement { name = "useproduct", public = true, protected = true, actions = function(name) process(v_product, name) end, arguments = "optional" }
818implement { name = "usecomponent", public = true, protected = true, actions = function(name) process(v_component, name) end, arguments = "optional" }
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837local start = {
838 [v_project] = "startprojectindeed",
839 [v_product] = "startproductindeed",
840 [v_component] = "startcomponentindeed",
841 [v_environment] = "startenvironmentindeed",
842}
843
844local stop = {
845 [v_project] = "stopprojectindeed",
846 [v_product] = "stopproductindeed",
847 [v_component] = "stopcomponentindeed",
848 [v_environment] = "stopenvironmentindeed",
849}
850
851local function gotonextlevel(what,name)
852 insert(stacks[what],name)
853 insert(typestack,currenttype)
854 currenttype = what
855 pushtree(what,name)
856 if start[what] then
857
858 token.expandmacro(start[what])
859 end
860end
861
862local function gotopreviouslevel(what)
863 if stop[what] then
864 token.expandmacro(stop[what])
865
866 end
867 poptree()
868 currenttype = remove(typestack) or v_text
869 remove(stacks[what])
870
871end
872
873local function autoname()
874 local name = scan_delimited(91,93) or scan_delimited(0,32)
875 if name == "*" then
876
877 name = nameonly(currentfile() or name)
878 end
879 return name
880end
881
882implement { name = "startproject", public = true, protected = true, actions = function() gotonextlevel(v_project, autoname()) end }
883implement { name = "startproduct", public = true, protected = true, actions = function() gotonextlevel(v_product, autoname()) end }
884implement { name = "startcomponent", public = true, protected = true, actions = function() gotonextlevel(v_component, autoname()) end }
885implement { name = "startenvironment", public = true, protected = true, actions = function() gotonextlevel(v_environment,autoname()) end }
886
887implement { name = "stopproject", public = true, protected = true, actions = function() gotopreviouslevel(v_project ) end }
888implement { name = "stopproduct", public = true, protected = true, actions = function() gotopreviouslevel(v_product ) end }
889implement { name = "stopcomponent", public = true, protected = true, actions = function() gotopreviouslevel(v_component ) end }
890implement { name = "stopenvironment", public = true, protected = true, actions = function() gotopreviouslevel(v_environment) end }
891
892implement { name = "currentproject", public = true, actions = function() context(topofstack(v_project )) end }
893implement { name = "currentproduct", public = true, actions = function() context(topofstack(v_product )) end }
894implement { name = "currentcomponent", public = true, actions = function() context(topofstack(v_component )) end }
895implement { name = "currentenvironment", public = true, actions = function() context(topofstack(v_environment)) end }
896
897
898
899
900
901
902
903
904
905
906
907local report_examodes = logs.reporter("system","examodes")
908
909local function convertexamodes(str)
910 local x = xml.convert(str)
911 for e in xml.collected(x,"exa:variable") do
912 local label = e.at and e.at.label
913 if label and label ~= "" then
914 local data = xml.text(e)
915 local mode = match(label,"^mode:(.+)$")
916 if mode then
917 context.enablemode { formatters["%s:%s"](mode,data) }
918 end
919 context.setvariable("exa:variables",label,(gsub(data,"([{}])","\\%1")))
920 end
921 end
922end
923
924function environment.loadexamodes(filename)
925 if not filename or filename == "" then
926
927 filename = removesuffix(tex.jobname)
928 end
929 filename = resolvers.findfile(addsuffix(filename,'ctm')) or ""
930 if filename ~= "" then
931 report_examodes("loading %a",filename)
932 convertexamodes(io.loaddata(filename))
933 else
934 report_examodes("no mode file %a",filename)
935 end
936end
937
938implement {
939 name = "loadexamodes",
940 actions = environment.loadexamodes,
941 public = true,
942 protected = true,
943 arguments = "optional"
944}
945
946
947
948
949
950
951document = document or {
952 arguments = allocate(),
953 files = allocate(),
954 variables = allocate(),
955 options = {
956 commandline = {
957 environments = allocate(),
958 modules = allocate(),
959 modes = allocate(),
960 },
961 ctxfile = {
962 environments = allocate(),
963 modules = allocate(),
964 modes = allocate(),
965 },
966 },
967 functions = table.setmetatablenewindex(function(t,k,v)
968 if rawget(t,k) then
969 report_functions("overloading document function %a",k)
970 end
971 rawset(t,k,v)
972 return v
973 end),
974}
975
976function document.setargument(key,value)
977 document.arguments[key] = value
978end
979
980function document.setdefaultargument(key,default)
981 local v = document.arguments[key]
982 if v == nil or v == "" then
983 document.arguments[key] = default
984 end
985end
986
987function document.setfilename(i,name)
988 if name then
989 document.files[tonumber(i)] = name
990 else
991 document.files[#document.files+1] = tostring(i)
992 end
993end
994
995function document.getargument(key,default)
996 local v = document.arguments[key]
997 if type(v) == "boolean" then
998 v = (v and "yes") or "no"
999 document.arguments[key] = v
1000 end
1001 return v or default or ""
1002end
1003
1004function document.getfilename(i)
1005 return document.files[tonumber(i)] or ""
1006end
1007
1008implement {
1009 name = "setdocumentargument",
1010 actions = document.setargument,
1011 arguments = "2 strings"
1012}
1013
1014implement {
1015 name = "setdocumentdefaultargument",
1016 actions = document.setdefaultargument,
1017 arguments = "2 strings"
1018}
1019
1020implement {
1021 name = "setdocumentfilename",
1022 actions = document.setfilename,
1023 arguments = { "integer", "string" }
1024}
1025
1026implement {
1027 name = "getdocumentargument",
1028 actions = { document.getargument, context },
1029 arguments = "2 strings"
1030}
1031
1032implement {
1033 name = "getdocumentfilename",
1034 actions = { document.getfilename, context },
1035 arguments = "integer"
1036}
1037
1038function document.setcommandline()
1039
1040
1041
1042 local arguments = document.arguments
1043 local files = document.files
1044 local options = document.options
1045
1046 for k, v in next, environment.arguments do
1047 k = gsub(k,"^c:","")
1048 if arguments[k] == nil then
1049 arguments[k] = v
1050 end
1051 end
1052
1053
1054
1055
1056
1057 if arguments.timing then
1058 context.usemodule { "timing" }
1059 end
1060
1061 if arguments.usage then
1062 trackers.enable("system.usage")
1063 end
1064
1065 if arguments.batchmode then
1066 context.batchmode(false)
1067 end
1068
1069 if arguments.nonstopmode then
1070 context.nonstopmode(false)
1071 end
1072
1073 if arguments.nostatistics then
1074 directives.enable("system.nostatistics")
1075 end
1076
1077 if arguments.paranoid then
1078 context.setvalue("maxreadlevel",1)
1079 end
1080
1081 if validstring(arguments.path) then
1082 context.usepath { arguments.path }
1083 end
1084
1085 if arguments.export then
1086 context.setupbackend { export = v_yes }
1087 end
1088
1089 local inputfile = validstring(arguments.input)
1090
1091 if inputfile and dirname(inputfile) == "." and lfs.isfile(inputfile) then
1092
1093 inputfile = basename(inputfile)
1094 end
1095
1096 local forcedruns = arguments.forcedruns
1097 local kindofrun = arguments.kindofrun
1098 local currentrun = arguments.currentrun
1099 local maxnofruns = arguments.maxnofruns or arguments.runs
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111 context.setupsystem {
1112 directory = validstring(arguments.setuppath),
1113 inputfile = inputfile,
1114 file = validstring(arguments.result),
1115 random = validstring(arguments.randomseed),
1116
1117 n = validstring(kindofrun),
1118 m = validstring(currentrun),
1119 }
1120
1121 forcedruns = tonumber(forcedruns) or 0
1122 kindofrun = tonumber(kindofrun) or 0
1123 maxnofruns = tonumber(maxnofruns) or 0
1124 currentrun = tonumber(currentrun) or 0
1125
1126 local prerollrun = forcedruns > 0 and currentrun > 0 and currentrun < forcedruns
1127
1128 environment.forcedruns = forcedruns
1129 environment.kindofrun = kindofrun
1130 environment.maxnofruns = maxnofruns
1131 environment.currentrun = currentrun
1132 environment.prerollrun = prerollrun
1133
1134 context.setconditional("prerollrun",prerollrun)
1135
1136 if validstring(arguments.arguments) then
1137 context.setupenv { arguments.arguments }
1138 end
1139
1140 if arguments.once then
1141 directives.enable("system.runonce")
1142 end
1143
1144 if arguments.noarrange then
1145 context.setuparranging { variables.disable }
1146 end
1147
1148
1149
1150 local commandline = options.commandline
1151
1152 commandline.environments = table.append(commandline.environments,settings_to_array(validstring(arguments.environment)))
1153 commandline.modules = table.append(commandline.modules, settings_to_array(validstring(arguments.usemodule)))
1154 commandline.modes = table.append(commandline.modes, settings_to_array(validstring(arguments.mode)))
1155
1156
1157
1158 if #files == 0 then
1159 local list = settings_to_array(validstring(arguments.files))
1160 if list and #list > 0 then
1161 files = list
1162 end
1163 end
1164
1165 if #files == 0 then
1166 files = { validstring(arguments.input) }
1167 end
1168
1169
1170
1171 document.arguments = arguments
1172 document.files = files
1173
1174end
1175
1176
1177
1178local function apply(list,action)
1179 if list then
1180 for i=1,#list do
1181 action { list[i] }
1182 end
1183 end
1184end
1185
1186function document.setmodes()
1187 apply(document.options.ctxfile .modes,context.enablemode)
1188 apply(document.options.commandline.modes,context.enablemode)
1189end
1190
1191function document.setmodules()
1192 apply(document.options.ctxfile .modules,context.usemodule)
1193 apply(document.options.commandline.modules,context.usemodule)
1194end
1195
1196function document.setenvironments()
1197 apply(document.options.ctxfile .environments,context.environment)
1198 apply(document.options.commandline.environments,context.environment)
1199end
1200
1201function document.setfilenames()
1202 local initialize = environment.initializefilenames
1203 if initialize then
1204 initialize()
1205 else
1206
1207 end
1208end
1209
1210implement { name = "setdocumentcommandline", actions = document.setcommandline, onlyonce = true }
1211implement { name = "setdocumentmodes", actions = document.setmodes, onlyonce = true }
1212implement { name = "setdocumentmodules", actions = document.setmodules, onlyonce = true }
1213implement { name = "setdocumentenvironments", actions = document.setenvironments, onlyonce = true }
1214implement { name = "setdocumentfilenames", actions = document.setfilenames, onlyonce = true }
1215
1216do
1217
1218 logs.registerfinalactions(function()
1219 local foundintrees = resolvers.foundintrees()
1220 if #foundintrees > 0 then
1221 logs.startfilelogging(report,"used files")
1222 for i=1,#foundintrees do
1223 report("%4i: % T",i,foundintrees[i])
1224 end
1225 logs.stopfilelogging()
1226 end
1227 end)
1228
1229 logs.registerfinalactions(function()
1230 local files = document.files
1231 local arguments = document.arguments
1232
1233 logs.startfilelogging(report,"commandline options")
1234 if arguments and next(arguments) then
1235 for argument, value in sortedhash(arguments) do
1236 report("%s=%A",argument,value)
1237 end
1238 else
1239 report("no arguments")
1240 end
1241 logs.stopfilelogging()
1242
1243 logs.startfilelogging(report,"commandline files")
1244 if files and #files > 0 then
1245 for i=1,#files do
1246 report("% 4i: %s",i,files[i])
1247 end
1248 else
1249 report("no files")
1250 end
1251 logs.stopfilelogging()
1252 end)
1253
1254end
1255
1256if environment.initex then
1257
1258 logs.registerfinalactions(function()
1259 local startfilelogging = logs.startfilelogging
1260 local stopfilelogging = logs.stopfilelogging
1261 startfilelogging(report,"stored tables")
1262 for k,v in sortedhash(storage.data) do
1263 report("%03i %s",k,v[1])
1264 end
1265 stopfilelogging()
1266 startfilelogging(report,"stored modules")
1267 for k,v in sortedhash(lua.bytedata) do
1268 report("%03i %s %s",k,v.name)
1269 end
1270 stopfilelogging()
1271 startfilelogging(report,"stored attributes")
1272 for k,v in sortedhash(attributes.names) do
1273 report("%03i %s",k,v)
1274 end
1275 stopfilelogging()
1276 startfilelogging(report,"stored catcodetables")
1277 for k,v in sortedhash(catcodes.names) do
1278 report("%03i % t",k,v)
1279 end
1280 stopfilelogging()
1281 startfilelogging(report,"stored corenamespaces")
1282 for k,v in sortedhash(interfaces.corenamespaces) do
1283 report("%03i %s",k,v)
1284 end
1285 stopfilelogging()
1286 end)
1287
1288end
1289
1290implement {
1291 name = "continueifinputfile",
1292 public = true,
1293 protected = true,
1294 arguments = "string",
1295 actions = function(inpname,basetoo)
1296 local inpnamefull = addsuffix(inpname,"tex")
1297 local inpfilefull = addsuffix(environment.inputfilename,"tex")
1298 local continue = inpnamefull == inpfilefull
1299
1300 if not continue then
1301 continue = inpnamefull == basename(inpfilefull)
1302 end
1303 if continue then
1304 report("continuing input file %a",inpname)
1305 else
1306 context.endinput()
1307 end
1308
1309 end
1310}
1311
1312
1313
1314local helpers = resolvers.finders.helpers
1315local validhashed = helpers.validhashed
1316local registerhashed = helpers.registerhashed
1317local registerfilescheme = helpers.registerfilescheme
1318
1319implement {
1320 name = "registerhashedfiles",
1321 public = true,
1322 protected = true,
1323 arguments = "optional",
1324 actions = function(list)
1325 for name in gmatch(list,"[^, ]+") do
1326 registerhashed(name)
1327 end
1328 end,
1329}
1330
1331implement {
1332 name = "registerfilescheme",
1333 public = true,
1334 protected = true,
1335 arguments = "optional",
1336 actions = function(list)
1337 for name in gmatch(list,"[^, ]+") do
1338 registerfilescheme(name)
1339 end
1340 end,
1341}
1342
1343implement {
1344 name = "doifelsevalidhashedfiles",
1345 public = true,
1346 protected = true,
1347 arguments = "string",
1348 actions = function(name)
1349 ctx_doifelse(validhashed(name))
1350 end,
1351}
1352
1353 |