1if 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", "dimension" },
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 = space^0
125local nospaces = spaces / ""
126local nohash = 1 - P("#")
127local digit = R("09")
128local double = P("##") / "#"
129local single = P("#")
130local sentinel = nospaces * (nohash^1 / "\\%0")
131local whatever = S("+-/*_^=:") + digit + R("AZ")
132local sargument = (single * digit)^1
133local dargument = (double * digit)^1
134local swhatever = (single * whatever)^1
135local dwhatever = (double * whatever)^1
136
137
138
139local global = nil
140local protected = nil
141local permanent = nil
142local expanded = nil
143local mutable = nil
144local immutable = nil
145local optional = nil
146local tolerant = nil
147local instance = nil
148local frozen = nil
149local csname = nil
150local rest = nil
151
152local function catcodes_s()
153 setcatcode(32,10)
154 setcatcode(13, 5)
155end
156
157local function catcodes_n()
158 setcatcode(32, 9)
159 setcatcode(13, 9)
160end
161
162local function oldoption(s)
163 if optional > 1 then
164 optional = optional - 1
165 return s .. "#*"
166 else
167 return s
168 end
169end
170
171local option = (
172 P("single") * Cc(1)
173 + P("double") * Cc(2)
174 + P("triple") * Cc(3)
175 + P("quadruple") * Cc(4)
176 + P("quintuple") * Cc(5)
177 + P("sixtuple")
178 ) * (P("empty") + P("argument"))
179
180local pattern = (
181 (
182 spaces * (
183 ( P("spaces") * space / catcodes_s )
184 + ( P("nospaces") * space / catcodes_n )
185 + ( P("global") * space / function() global = true end)
186 + ( P("protected") * space / function() protected = 1 end)
187 + ( P("semiprotected") * space / function() protected = 2 end)
188 + ( P("permanent") * space / function() permanent = true end)
189 + ( P("expanded") * space / function() expanded = true end)
190 + ( P("tolerant") * space / function() tolerant = true end)
191 + ( P("instance") * space / function() instance = true end)
192 + ( P("frozen") * space / function() frozen = true end)
193 + ( P("mutable") * space / function() mutable = true end)
194 + ( P("immutable") * space / function() immutable = true end)
195 + ( P("unexpanded") * space / function() protected = 1 end)
196 + ( option * space / function(s) tolerant = true
197 optional = s end)
198 )
199 )^0
200 * spaces * ( C((1-S(" #["))^1) )
201 * spaces * Cs(
202 (Cs(P("[") * dargument * P("]")) / oldoption + nospaces * dwhatever)^1 * sentinel^-1 * double^-1
203 + (Cs(P("[") * sargument * P("]")) / oldoption + nospaces * swhatever)^1 * sentinel^-1 * single^-1
204 + sentinel^-1 * (double+single)^-1
205 )
206)
207
208local ctx_dostarttexdefinition = context.dostarttexdefinition
209
210local function texdefinition_one(str)
211 global = false
212 protected = false
213 permanent = false
214 expanded = false
215 mutable = false
216 immutable = false
217 optional = 0
218 tolerant = false
219 instance = false
220 frozen = false
221 csname, rest = lpegmatch(pattern,str)
222
223
224
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 == 1 and [[\protected]] or [[\semiprotected]]) 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 = "tokenstring" }
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 = { "dimension", "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 boolean_value <const> = tokens.values.boolean
388
389local hash = utilities.parsers.hashes.settings_to_set
390
391implement {
392 name = "if_common",
393 usage = "condition",
394 arguments = "2 arguments",
395 actions = function(a,b)
396 if a == b then
397 setmacro("commalistelement",a)
398 return boolean_value, a ~= ""
399 end
400 local ba = find(a,",",1,true)
401 local bb = find(b,",",1,true)
402 if ba and bb then
403 local ha = hash[a]
404 local hb = hash[b]
405 for k in next, ha do
406 if hb[k] then
407 setmacro("commalistelement",k)
408 return boolean_value, true
409 end
410 end
411 elseif ba then
412 if hash[a][b] then
413 setmacro("commalistelement",b)
414 return boolean_value, true
415 end
416 elseif bb then
417 if hash[b][a] then
418 setmacro("commalistelement",a)
419 return boolean_value, true
420 end
421 end
422 setmacro("commalistelement","")
423 return boolean_value, false
424 end
425}
426
427implement {
428 name = "ifcommon",
429 public = true,
430 usage = "condition",
431 arguments = "2 arguments",
432 actions = function(a,b)
433 if a == b then
434 return boolean_value, a ~= ""
435 end
436 local ba = find(a,",",1,true)
437 local bb = find(b,",",1,true)
438 if ba and bb then
439 local ha = hash[a]
440 local hb = hash[b]
441 for k in next, ha do
442 if hb[k] then
443 return boolean_value, true
444 end
445 end
446 elseif ba then
447 if hash[a][b] then
448 return boolean_value, true
449 end
450 elseif bb then
451 if hash[b][a] then
452 return boolean_value, true
453 end
454 end
455 return boolean_value, false
456 end
457}
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482implement {
483 name = "ifinset",
484 public = true,
485 usage = "condition",
486 arguments = "2 arguments",
487 actions = function(a,b)
488 if a == b then
489 return boolean_value, a ~= ""
490 end
491 local bb = find(b,",",1,true)
492 if bb then
493 if hash[b][a] then
494 return boolean_value, true
495 end
496 end
497 return boolean_value, false
498 end
499}
500
501local bp = number.dimenfactors.bp
502
503implement {
504 name = "tobigpoints",
505 actions = function(d) context("%.5F",bp * d) end,
506 arguments = "dimension",
507}
508
509implement {
510 name = "towholebigpoints",
511 actions = function(d) context("%r",bp * d) end,
512 arguments = "dimension",
513}
514
515
516
517local function getshape(s)
518 local t = texget(s)
519 local n = t and #t or 0
520 context(n)
521 if n > 0 then
522 for i=1,n do
523 local ti = t[i]
524 if type(ti) == "table" then
525 context(" %isp %isp",ti[1],ti[2])
526 else
527 context(" %i",ti)
528 end
529 end
530 end
531end
532
533implement {
534 name = "getparshape",
535 public = true,
536 actions = function() getshape("parshape") end,
537}
538implement {
539 name = "getclubpenalties",
540 public = true,
541 actions = function() getshape("clubpenalties") end,
542}
543implement {
544 name = "getinterlinepenalties",
545 public = true,
546 actions = function() getshape("interlinepenalties") end,
547 }
548implement {
549 name = "getdisplaywidowpenalties",
550 public = true,
551 actions = function() getshape("displaywidowpenalties") end,
552}
553implement {
554 name = "getwidowpenalties",
555 public = true,
556 actions = function() getshape("widowpenalties") end,
557}
558
559
560
561implement {
562 name = "loopcs",
563 public = true,
564 arguments = { "integer", "csname" },
565 actions = function(n,cs)
566 local c = context[cs]
567 if n < 0 then
568 for i=-n,1 do c() end
569 else
570 for i= 1,n do c() end
571 end
572 end
573}
574
575implement {
576 name = "loopcsn",
577 public = true,
578 arguments = { "integer", "csname" },
579 actions = function(n,cs)
580 local c = context[cs]
581 if n < 0 then
582 for i=-n,1 do c(i) end
583 else
584 for i= 1,n do c(i) end
585 end
586 end
587}
588
589local output = io.output
590
591implement {
592 name = "nologbuffering",
593 public = true,
594 protected = true,
595 actions = function()
596 output():setvbuf("no")
597 end,
598}
599
600implement {
601 name = "linebuffering",
602 public = true,
603 protected = true,
604 actions = function()
605 output():setvbuf("line")
606 end,
607}
608 |