1 if not modules then modules = { } end modules ['syst-aux'] = {
2 version = 1.001,
3 comment = "companion to syst-aux.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
12
13
14local tonumber, next, type = tonumber, next, type
15local utfsub = utf.sub
16local P, S, R, C, Cc, Cs, Carg, lpegmatch = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Carg, lpeg.match
17local find, formatters = string.find, string.formatters
18
19local context = context
20local implement = interfaces.implement
21local setmacro = interfaces.setmacro
22local setcatcode = tex.setcatcode
23local texget = tex.get
24local utf8character = lpeg.patterns.utf8character
25local settings_to_array = utilities.parsers.settings_to_array
26local settings_to_set = utilities.parsers.settings_to_set
27
28local pattern = C(utf8character^-1) * C(P(1)^0)
29
30implement {
31 name = "getfirstcharacter",
32 arguments = "string",
33 actions = function(str)
34 local first, rest = lpegmatch(pattern,str)
35 setmacro("firstcharacter",first)
36 setmacro("remainingcharacters",rest)
37 end
38}
39
40implement {
41 name = "thefirstcharacter",
42 arguments = "string",
43 actions = function(str)
44 local first, rest = lpegmatch(pattern,str)
45 context(first)
46 end
47}
48
49implement {
50 name = "theremainingcharacters",
51 arguments = "string",
52 actions = function(str)
53 local first, rest = lpegmatch(pattern,str)
54 context(rest)
55 end
56}
57
58local pattern = C(utf8character^-1)
59local ctx_doifelse = commands.doifelse
60
61implement {
62 name = "doifelsefirstchar",
63 arguments = "2 strings",
64 actions = function(str,chr)
65 ctx_doifelse(lpegmatch(pattern,str) == chr)
66 end
67}
68
69implement {
70 name = "getsubstring",
71 arguments = "3 strings",
72 actions = function(str,first,last)
73 context(utfsub(str,tonumber(first),tonumber(last)))
74 end
75}
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107local pattern = (C((1-P("%"))^1) * Carg(1)) / function(n,d)
108 return formatters["%.0fsp"](d * tonumber(n)/100) end * P("%") * P(-1)
109
110
111
112implement {
113 name = "percentageof",
114 arguments = { "string", "dimen" },
115 actions = function(str,dim)
116 context(lpegmatch(pattern,str,1,dim) or str)
117 end
118}
119
120
121
122
123local space = P(" ") / ""
124local spaces = P(" ")^0 / ""
125local nohash = 1 - P("#")
126local digit = R("09")
127local double = P("##") / "#"
128local single = P("#")
129local sentinel = spaces * (nohash^1 / "\\%0")
130local whatever = S("+-/*_^=:") + digit
131local sargument = (single * digit)^1
132local dargument = (double * digit)^1
133local swhatever = (single * whatever)^1
134local dwhatever = (double * whatever)^1
135
136
137
138local space = P(" ")
139local spaces = space^0
140
141
142
143local global = nil
144local protected = nil
145local permanent = nil
146local expanded = nil
147local mutable = nil
148local immutable = nil
149local optional = nil
150local tolerant = nil
151local instance = nil
152local frozen = nil
153local csname = nil
154local rest = nil
155
156local function catcodes_s()
157 setcatcode(32,10)
158 setcatcode(13, 5)
159end
160
161local function catcodes_n()
162 setcatcode(32, 9)
163 setcatcode(13, 9)
164end
165
166local function oldoption(s)
167 if optional > 1 then
168 optional = optional - 1
169 return s .. "#*"
170 else
171 return s
172 end
173end
174
175local option = (
176 P("single") * Cc(1)
177 + P("double") * Cc(2)
178 + P("triple") * Cc(3)
179 + P("quadruple") * Cc(4)
180 + P("quintuple") * Cc(5)
181 + P("sixtuple")
182 ) * (P("empty") + P("argument"))
183
184local pattern = (
185 (
186 spaces * (
187 ( P("spaces") * space / catcodes_s )
188 + ( P("nospaces") * space / catcodes_n )
189 + ( P("global") * space / function() global = true end)
190 + ( P("protected") * space / function() protected = true end)
191 + ( P("permanent") * space / function() permanent = true end)
192 + ( P("expanded") * space / function() expanded = true end)
193 + ( P("tolerant") * space / function() tolerant = true end)
194 + ( P("instance") * space / function() instance = true end)
195 + ( P("frozen") * space / function() frozen = true end)
196 + ( P("mutable") * space / function() mutable = true end)
197 + ( P("immutable") * space / function() immutable = true end)
198 + ( P("unexpanded") * space / function() protected = true end)
199 + ( option * space / function(s) tolerant = true
200 optional = s end)
201 )
202 )^0
203 * spaces * ( C((1-S(" #["))^1) )
204 * spaces * Cs(
205 (Cs(P("[") * dargument * P("]")) / oldoption + dwhatever)^1 * sentinel^-1 * double^-1
206 + (Cs(P("[") * sargument * P("]")) / oldoption + swhatever)^1 * sentinel^-1 * single^-1
207 + sentinel^-1 * (double+single)^-1
208 )
209)
210
211local ctx_dostarttexdefinition = context.dostarttexdefinition
212
213local function texdefinition_one(str)
214 global = false
215 protected = false
216 permanent = false
217 expanded = false
218 mutable = false
219 immutable = false
220 optional = 0
221 tolerant = false
222 instance = false
223 frozen = false
224 csname, rest = lpegmatch(pattern,str)
225 ctx_dostarttexdefinition()
226end
227
228local function texdefinition_two()
229 context (
230 (tolerant and [[\tolerant]] or "") ..
231 (frozen and [[\frozen]] or "") ..
232 (protected and [[\protected]] or "") ..
233 (permanent and [[\permanent]] or "") ..
234 (instance and [[\instance]] or "") ..
235 (mutable and [[\mutable]] or "") ..
236 (immutable and [[\immutable]] or "") ..
237
238
239 (global and (expanded and [[\xdefcsname ]] or [[\gdefcsname ]]) or (expanded and [[\edefcsname ]] or [[\defcsname ]])) ..
240 csname .. [[\endcsname ]] ..
241 rest
242 )
243end
244
245implement { name = "texdefinition_one", actions = texdefinition_one, scope = "private", arguments = "string" }
246implement { name = "texdefinition_two", actions = texdefinition_two, scope = "private" }
247
248do
249
250
251
252
253 local _lower_, _upper_, _strip_
254
255 _lower_ = function(s)
256 if characters and characters.lower then
257 _lower_ = characters.lower
258 return _lower_(s)
259 end
260 return string.lower(s)
261 end
262
263 _upper_ = function(s)
264 if characters and characters.upper then
265 _upper_ = characters.upper
266 return _upper_(s)
267 end
268 return string.upper(s)
269 end
270
271 _strip_ = function(s)
272
273 if string.strip then
274 _strip_ = string.strip
275 return _strip_(s)
276 end
277 return s
278 end
279
280 local function lower(s) context(_lower_(s)) end
281 local function upper(s) context(_upper_(s)) end
282 local function strip(s) context(_strip_(s)) end
283
284 implement { name = "upper", arguments = "string", actions = upper }
285 implement { name = "lower", arguments = "string", actions = lower }
286 implement { name = "strip", arguments = "string", actions = strip }
287
288end
289
290implement {
291 name = "converteddimen",
292 arguments = { "dimen", "string" },
293 actions = function(dimen,unit)
294 context(number.todimen(dimen,unit or "pt","%0.5f"))
295 end
296}
297
298
299
300implement {
301 name = "immediatemessage",
302 public = true,
303 arguments = { "'message'", "string" },
304 actions = logs.status
305}
306
307implement {
308 name = "writestring",
309 public = true,
310 protected = true,
311 arguments = "string",
312 actions = function (s)
313 logs.writer(s,"\n")
314 end,
315}
316
317implement {
318 name = "writeline",
319 public = true,
320 protected = true,
321 actions = logs.newline,
322}
323
324implement {
325 name = "resettimer",
326 actions = function()
327 statistics.resettiming("whatever")
328 statistics.starttiming("whatever")
329 end
330}
331
332implement {
333 name = "benchmarktimer",
334 actions = function()
335 statistics.benchmarktimer("whatever")
336 end
337}
338
339implement {
340 name = "elapsedtime",
341 actions = function()
342 statistics.stoptiming("whatever")
343 context(statistics.elapsedtime("whatever"))
344 end
345}
346
347implement {
348 name = "elapsedsteptime",
349 arguments = "integer",
350 actions = function(n)
351 statistics.stoptiming("whatever")
352 local t = statistics.elapsed("whatever")/(n > 0 and n or 1)
353 if t > 0 then
354 context("%0.9f",t)
355 else
356 context(0)
357 end
358 end
359}
360
361local accuracy = table.setmetatableindex(function(t,k)
362 local v = formatters["%0." ..k .. "f"]
363 t[k] = v
364 return v
365end)
366
367implement {
368 name = "rounded",
369 arguments = "integer",
370 actions = function(n,m) context(accuracy[n](m)) end
371}
372
373
374
375local ctx_protected_cs = context.protected.cs
376
377local ctx_firstoftwoarguments = ctx_protected_cs.firstoftwoarguments
378local ctx_secondoftwoarguments = ctx_protected_cs.secondoftwoarguments
379local ctx_firstofoneargument = ctx_protected_cs.firstofoneargument
380local ctx_gobbleoneargument = ctx_protected_cs.gobbleoneargument
381
382context.firstoftwoarguments = ctx_firstoftwoarguments
383context.secondoftwoarguments = ctx_secondoftwoarguments
384context.firstofoneargument = ctx_firstofoneargument
385context.gobbleoneargument = ctx_gobbleoneargument
386
387local ctx_iftrue = context.iftrue
388local ctx_iffalse = context.iffalse
389
390local hash = utilities.parsers.hashes.settings_to_set
391
392local function doifelsecommon(a,b)
393 if a == b then
394 setmacro("commalistelement",a)
395 if a == "" then
396 ctx_secondoftwoarguments()
397 else
398 ctx_firstoftwoarguments()
399 end
400 return
401 end
402 local ba = find(a,",",1,true)
403 local bb = find(b,",",1,true)
404 if ba and bb then
405 local ha = hash[a]
406 local hb = hash[b]
407
408
409 for k in next, ha do
410 if hb[k] then
411 setmacro("commalistelement",k)
412 ctx_firstoftwoarguments()
413 return
414 end
415 end
416 elseif ba then
417 if hash[a][b] then
418
419 setmacro("commalistelement",b)
420 ctx_firstoftwoarguments()
421 return
422 end
423 elseif bb then
424 if hash[b][a] then
425
426 setmacro("commalistelement",a)
427 ctx_firstoftwoarguments()
428 return
429 end
430 end
431 setmacro("commalistelement","")
432 ctx_secondoftwoarguments()
433end
434
435local function doifcommon(a,b)
436 if a == b then
437 setmacro("commalistelement",a)
438 if a == "" then
439 ctx_gobbleoneargument()
440 else
441 ctx_firstofoneargument()
442 end
443 return
444 end
445 local ba = find(a,",",1,true)
446 local bb = find(b,",",1,true)
447 if ba and bb then
448 local ha = hash[a]
449 local hb = hash[b]
450
451
452 for k in next, ha do
453 if hb[k] then
454 setmacro("commalistelement",k)
455 ctx_firstofoneargument()
456 return
457 end
458 end
459 elseif ba then
460 if hash[a][b] then
461
462 setmacro("commalistelement",b)
463 ctx_firstofoneargument()
464 return
465 end
466 elseif bb then
467 if hash[b][a] then
468
469 setmacro("commalistelement",a)
470 ctx_firstofoneargument()
471 return
472 end
473 end
474 setmacro("commalistelement","")
475 ctx_gobbleoneargument()
476end
477
478local function doifnotcommon(a,b)
479 if a == b then
480 setmacro("commalistelement",a)
481 if a == "" then
482 ctx_firstofoneargument()
483 else
484 ctx_gobbleoneargument()
485 end
486 return
487 end
488 local ba = find(a,",",1,true)
489 local bb = find(b,",",1,true)
490 if ba and bb then
491 local ha = hash[a]
492 local hb = hash[b]
493
494
495 for k in next, ha do
496 if hb[k] then
497 setmacro("commalistelement",k)
498 ctx_gobbleoneargument()
499 return
500 end
501 end
502 elseif ba then
503 if hash[a][b] then
504
505 setmacro("commalistelement",b)
506 ctx_gobbleoneargument()
507 return
508 end
509 elseif bb then
510 if hash[b][a] then
511
512 setmacro("commalistelement",a)
513 ctx_gobbleoneargument()
514 return
515 end
516 end
517 setmacro("commalistelement","")
518 ctx_firstofoneargument()
519end
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560local function doifelseinset(a,b)
561 if a == b then
562 setmacro("commalistelement",a)
563 if a == "" then
564 ctx_secondoftwoarguments()
565 else
566 ctx_firstoftwoarguments()
567 end
568 return
569 end
570 local bb = find(b,",",1,true)
571 if bb then
572 if hash[b][a] then
573
574 setmacro("commalistelement",a)
575 ctx_firstoftwoarguments()
576 return
577 end
578 end
579 setmacro("commalistelement","")
580 ctx_secondoftwoarguments()
581end
582
583local function doifinset(a,b)
584 if a == b then
585 setmacro("commalistelement",a)
586 if a == "" then
587 ctx_gobbleoneargument()
588 else
589 ctx_firstofoneargument()
590 end
591 return
592 end
593 local bb = find(b,",",1,true)
594 if bb then
595 if hash[b][a] then
596
597 setmacro("commalistelement",a)
598 ctx_firstofoneargument()
599 return
600 end
601 end
602 setmacro("commalistelement","")
603 ctx_gobbleoneargument()
604end
605
606local function doifnotinset(a,b)
607 if a == b then
608 setmacro("commalistelement",a)
609 if a == "" then
610 ctx_firstofoneargument()
611 else
612 ctx_gobbleoneargument()
613 end
614 return
615 end
616 local bb = find(b,",",1,true)
617 if bb then
618 if hash[b][a] then
619
620 setmacro("commalistelement",a)
621 ctx_gobbleoneargument()
622 return
623 end
624 end
625 setmacro("commalistelement","")
626 ctx_firstofoneargument()
627end
628
629implement {
630 name = "doifelsecommon",
631 actions = doifelsecommon,
632 arguments = "2 strings",
633}
634
635implement {
636 name = "doifcommon",
637 actions = doifcommon,
638 arguments = "2 strings",
639}
640
641implement {
642 name = "doifnotcommon",
643 actions = doifnotcommon,
644 arguments = "2 strings",
645}
646
647
648
649
650
651
652
653
654implement {
655 name = "doifelseinset",
656 actions = doifelseinset,
657 arguments = "2 strings",
658
659}
660
661implement {
662 name = "doifinset",
663 actions = doifinset,
664 arguments = "2 strings",
665}
666
667implement {
668 name = "doifnotinset",
669 actions = doifnotinset,
670 arguments = "2 strings",
671}
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726local bp = number.dimenfactors.bp
727
728implement {
729 name = "tobigpoints",
730 actions = function(d) context("%.5F",bp * d) end,
731 arguments = "dimension",
732}
733
734implement {
735 name = "towholebigpoints",
736 actions = function(d) context("%r",bp * d) end,
737 arguments = "dimension",
738}
739
740
741
742local function getshape(s)
743 local t = texget(s)
744 local n = t and #t or 0
745 context(n)
746 if n > 0 then
747 for i=1,n do
748 local ti = t[i]
749 if type(ti) == "table" then
750 context(" %isp %isp",ti[1],ti[2])
751 else
752 context(" %i",ti)
753 end
754 end
755 end
756end
757
758implement {
759 name = "getparshape",
760 public = true,
761 actions = function() getshape("parshape") end,
762}
763implement {
764 name = "getclubpenalties",
765 public = true,
766 actions = function() getshape("clubpenalties") end,
767}
768implement {
769 name = "getinterlinepenalties",
770 public = true,
771 actions = function() getshape("interlinepenalties") end,
772 }
773implement {
774 name = "getdisplaywidowpenalties",
775 public = true,
776 actions = function() getshape("displaywidowpenalties") end,
777}
778implement {
779 name = "getwidowpenalties",
780 public = true,
781 actions = function() getshape("widowpenalties") end,
782}
783
784implement {
785 name = "loopcs",
786 public = true,
787 arguments = { "integerargument", "csname" },
788 actions = function(n,cs)
789 local c = context[cs]
790 if n < 0 then
791 for i=-n,1 do c() end
792 else
793 for i= 1,n do c() end
794 end
795 end
796}
797implement {
798 name = "loopcsn",
799 public = true,
800 arguments = { "integerargument", "csname" },
801 actions = function(n,cs)
802 local c = context[cs]
803 if n < 0 then
804 for i=-n,1 do c(i) end
805 else
806 for i= 1,n do c(i) end
807 end
808 end
809}
810 |