strc-ref.lua /size: 91 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
strc-ref
'
]
=
{
2
version
=
1
.
001
,
3
comment
=
"
companion to strc-ref.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
-- beware, this is a first step in the rewrite (just getting rid of
10
-- the tuo file); later all access and parsing will also move to lua
11 12
-- the useddata and pagedata names might change
13
-- todo: pack exported data
14 15
-- todo: autoload components when :::
16 17
local
format
,
find
,
gmatch
,
match
,
strip
=
string
.
format
,
string
.
find
,
string
.
gmatch
,
string
.
match
,
string
.
strip
18
local
floor
=
math
.
floor
19
local
rawget
,
tonumber
,
type
,
next
=
rawget
,
tonumber
,
type
,
next
20
local
lpegmatch
=
lpeg
.
match
21
local
insert
,
remove
,
copytable
=
table
.
insert
,
table
.
remove
,
table
.
copy
22
local
formatters
=
string
.
formatters
23
local
P
,
Cs
,
lpegmatch
=
lpeg
.
P
,
lpeg
.
Cs
,
lpeg
.
match
24 25
local
allocate
=
utilities
.
storage
.
allocate
26
local
mark
=
utilities
.
storage
.
mark
27
local
setmetatableindex
=
table
.
setmetatableindex
28 29
local
trace_referencing
=
false
trackers
.
register
(
"
structures.referencing
"
,
function
(
v
)
trace_referencing
=
v
end
)
30
local
trace_analyzing
=
false
trackers
.
register
(
"
structures.referencing.analyzing
"
,
function
(
v
)
trace_analyzing
=
v
end
)
31
local
trace_identifying
=
false
trackers
.
register
(
"
structures.referencing.identifying
"
,
function
(
v
)
trace_identifying
=
v
end
)
32
local
trace_importing
=
false
trackers
.
register
(
"
structures.referencing.importing
"
,
function
(
v
)
trace_importing
=
v
end
)
33
local
trace_empty
=
false
trackers
.
register
(
"
structures.referencing.empty
"
,
function
(
v
)
trace_empty
=
v
end
)
34 35
local
check_duplicates
=
true
36 37
directives
.
register
(
"
structures.referencing.checkduplicates
"
,
function
(
v
)
check_duplicates
=
v
end
)
38 39
local
report_references
=
logs
.
reporter
(
"
references
"
)
40
local
report_identifying
=
logs
.
reporter
(
"
references
"
,
"
identifying
"
)
41
local
report_importing
=
logs
.
reporter
(
"
references
"
,
"
importing
"
)
42
local
report_empty
=
logs
.
reporter
(
"
references
"
,
"
empty
"
)
43
local
report
=
report_references
44 45
local
variables
=
interfaces
.
variables
46
local
v_page
=
variables
.
page
47
local
v_auto
=
variables
.
auto
48
local
v_yes
=
variables
.
yes
49
local
v_name
=
variables
.
name
50 51
local
context
=
context
52
local
commands
=
commands
53
local
implement
=
interfaces
.
implement
54 55
local
ctx_latelua
=
context
.
latelua
56 57
local
texgetcount
=
tex
.
getcount
58
local
texsetcount
=
tex
.
setcount
59
local
texconditionals
=
tex
.
conditionals
60 61
local
productcomponent
=
resolvers
.
jobs
.
productcomponent
62
local
justacomponent
=
resolvers
.
jobs
.
justacomponent
63 64
local
settings_to_array
=
utilities
.
parsers
.
settings_to_array
65
local
settings_to_table
=
utilities
.
parsers
.
settings_to_array_obey_fences
66
local
process_settings
=
utilities
.
parsers
.
process_stripped_settings
67
local
unsetvalue
=
attributes
.
unsetvalue
68 69
local
structures
=
structures
70
local
helpers
=
structures
.
helpers
71
local
sections
=
structures
.
sections
72
local
references
=
structures
.
references
73
local
lists
=
structures
.
lists
74
local
counters
=
structures
.
counters
75 76
local
jobpositions
=
job
.
positions
77
local
getpos
=
jobpositions
.
getpos
78 79
-- some might become local
80 81
references
.
defined
=
references
.
defined
or
allocate
(
)
82 83
local
defined
=
references
.
defined
84
local
derived
=
allocate
(
)
85
local
specials
=
allocate
(
)
86
local
functions
=
allocate
(
)
87
local
runners
=
allocate
(
)
88
local
internals
=
allocate
(
)
89
local
filters
=
allocate
(
)
90
local
executers
=
allocate
(
)
91
local
handlers
=
allocate
(
)
92
local
tobesaved
=
allocate
(
)
93
local
collected
=
allocate
(
)
94
local
tobereferred
=
allocate
(
)
95
local
referred
=
allocate
(
)
96
local
usedinternals
=
allocate
(
)
97
local
flaginternals
=
allocate
(
)
98
local
usedviews
=
allocate
(
)
99 100
references
.
derived
=
derived
101
references
.
specials
=
specials
102
references
.
functions
=
functions
103
references
.
runners
=
runners
104
references
.
internals
=
internals
105
references
.
filters
=
filters
106
references
.
executers
=
executers
107
references
.
handlers
=
handlers
108
references
.
tobesaved
=
tobesaved
109
references
.
collected
=
collected
110
references
.
tobereferred
=
tobereferred
111
references
.
referred
=
referred
112
references
.
usedinternals
=
usedinternals
113
references
.
flaginternals
=
flaginternals
114
references
.
usedviews
=
usedviews
115 116
local
splitreference
=
references
.
splitreference
117
local
splitprefix
=
references
.
splitcomponent
-- replaces: references.splitprefix
118
local
prefixsplitter
=
references
.
prefixsplitter
119
local
componentsplitter
=
references
.
componentsplitter
120 121
local
currentreference
=
nil
122 123
local
txtcatcodes
=
catcodes
.
numbers
.
txtcatcodes
-- or just use "txtcatcodes"
124 125
local
context
=
context
126 127
local
ctx_pushcatcodes
=
context
.
pushcatcodes
128
local
ctx_popcatcodes
=
context
.
popcatcodes
129
local
ctx_dofinishreference
=
context
.
dofinishreference
130
local
ctx_dofromurldescription
=
context
.
dofromurldescription
131
local
ctx_dofromurlliteral
=
context
.
dofromurlliteral
132
local
ctx_dofromfiledescription
=
context
.
dofromfiledescription
133
local
ctx_dofromfileliteral
=
context
.
dofromfileliteral
134
local
ctx_expandreferenceoperation
=
context
.
expandreferenceoperation
135
local
ctx_expandreferencearguments
=
context
.
expandreferencearguments
136
local
ctx_convertnumber
=
context
.
convertnumber
137
local
ctx_emptyreference
=
context
.
emptyreference
138 139
storage
.
register
(
"
structures/references/defined
"
,
references
.
defined
,
"
structures.references.defined
"
)
140 141
local
initializers
=
{
}
142
local
finalizers
=
{
}
143
local
somefound
=
false
-- so we don't report missing when we have a fresh start
144 145
function
references
.
registerinitializer
(
func
)
-- we could use a token register instead
146
initializers
[
#
initializers
+
1
]
=
func
147
end
148 149
function
references
.
registerfinalizer
(
func
)
-- we could use a token register instead
150
finalizers
[
#
finalizers
+
1
]
=
func
151
end
152 153
local
function
initializer
(
)
-- can we use a tobesaved as metatable for collected?
154
tobesaved
=
references
.
tobesaved
155
collected
=
references
.
collected
156
for
i
=
1
,
#
initializers
do
157
initializers
[
i
]
(
tobesaved
,
collected
)
158
end
159
for
prefix
,
list
in
next
,
collected
do
160
for
tag
,
data
in
next
,
list
do
161
local
r
=
data
.
references
162
local
i
=
r
.
internal
163
if
i
then
164
internals
[
i
]
=
data
165
usedinternals
[
i
]
=
r
.
used
166
end
167
end
168
end
169
somefound
=
next
(
collected
)
170
end
171 172
local
function
finalizer
(
)
173
for
i
=
1
,
#
finalizers
do
174
finalizers
[
i
]
(
tobesaved
)
175
end
176
for
prefix
,
list
in
next
,
tobesaved
do
177
for
tag
,
data
in
next
,
list
do
178
local
r
=
data
.
references
179
local
i
=
r
.
internal
180
local
f
=
flaginternals
[
i
]
181
if
f
then
182
r
.
used
=
usedviews
[
i
]
or
true
183
end
184
end
185
end
186
end
187 188
job
.
register
(
'
structures.references.collected
'
,
tobesaved
,
initializer
,
finalizer
)
189 190
local
maxreferred
=
1
191
local
nofreferred
=
0
192 193
local
function
initializer
(
)
-- can we use a tobesaved as metatable for collected?
194
tobereferred
=
references
.
tobereferred
195
referred
=
references
.
referred
196
nofreferred
=
#
referred
197
end
198 199
-- no longer done this way
200 201
-- references.resolvers = references.resolvers or { }
202
-- local resolvers = references.resolvers
203
--
204
-- function resolvers.section(var)
205
-- local vi = lists.collected[var.i[2]]
206
-- if vi then
207
-- var.i = vi
208
-- var.r = (vi.references and vi.references.realpage) or (vi.pagedata and vi.pagedata.realpage) or 1
209
-- else
210
-- var.i = nil
211
-- var.r = 1
212
-- end
213
-- end
214
--
215
-- resolvers.float = resolvers.section
216
-- resolvers.description = resolvers.section
217
-- resolvers.formula = resolvers.section
218
-- resolvers.note = resolvers.section
219
--
220
-- function resolvers.reference(var)
221
-- local vi = var.i[2]
222
-- if vi then
223
-- var.i = vi
224
-- var.r = (vi.references and vi.references.realpage) or (vi.pagedata and vi.pagedata.realpage) or 1
225
-- else
226
-- var.i = nil
227
-- var.r = 1
228
-- end
229
-- end
230 231
-- We make the array sparse (maybe a finalizer should optionally return a table) because
232
-- there can be quite some page links involved. We only store one action number per page
233
-- which is normally good enough for what we want (e.g. see above/below) and we do
234
-- a combination of a binary search and traverse backwards. A previous implementation
235
-- always did a traverse and was pretty slow on a large number of links (given that this
236
-- methods was used). It took me about a day to locate this as a bottleneck in processing
237
-- a 2500 page interactive document with 60 links per page. In that case, traversing
238
-- thousands of slots per link then brings processing to a grinding halt (especially when
239
-- there are no slots at all, which is the case in a first run).
240 241
local
sparsetobereferred
=
{
}
242 243
local
function
finalizer
(
)
244
local
lastr
,
lasti
245
local
n
=
0
246
for
i
=
1
,
maxreferred
do
247
local
r
=
tobereferred
[
i
]
248
if
not
lastr
then
249
lastr
=
r
250
lasti
=
i
251
elseif
r
~
=
lastr
then
252
n
=
n
+
1
253
sparsetobereferred
[
n
]
=
{
lastr
,
lasti
}
254
lastr
=
r
255
lasti
=
i
256
end
257
end
258
if
lastr
then
259
n
=
n
+
1
260
sparsetobereferred
[
n
]
=
{
lastr
,
lasti
}
261
end
262
end
263 264
job
.
register
(
'
structures.references.referred
'
,
sparsetobereferred
,
initializer
,
finalizer
)
265 266
local
function
referredpage
(
n
)
267
local
max
=
nofreferred
268
if
max
>
0
then
269
-- find match
270
local
min
=
1
271
while
true
do
272
local
mid
=
floor
(
(
min
+
max
)
/
2
)
273
local
r
=
referred
[
mid
]
274
local
m
=
r
[
2
]
275
if
n
=
=
m
then
276
return
r
[
1
]
277
elseif
n
>
m
then
278
min
=
mid
+
1
279
else
280
max
=
mid
-
1
281
end
282
if
min
>
max
then
283
break
284
end
285
end
286
-- find first previous
287
for
i
=
min
,
1
,
-1
do
288
local
r
=
referred
[
i
]
289
if
r
and
r
[
2
]
<
n
then
290
return
r
[
1
]
291
end
292
end
293
end
294
-- fallback
295
return
texgetcount
(
"
realpageno
"
)
296
end
297 298
references
.
referredpage
=
referredpage
299 300
function
references
.
registerpage
(
n
)
-- called in the backend code
301
if
not
tobereferred
[
n
]
then
302
if
n
>
maxreferred
then
303
maxreferred
=
n
304
end
305
tobereferred
[
n
]
=
texgetcount
(
"
realpageno
"
)
306
end
307
end
308 309
-- todo: delay split till later as in destinations we split anyway
310 311
local
orders
,
lastorder
=
{
}
,
0
312 313
local
function
setnextorder
(
kind
,
name
)
314
lastorder
=
0
315
if
kind
and
name
then
316
local
ok
=
orders
[
kind
]
317
if
not
ok
then
318
ok
=
{
}
319
orders
[
kind
]
=
ok
320
end
321
lastorder
=
(
ok
[
name
]
or
0
)
+
1
322
ok
[
name
]
=
lastorder
323
end
324
texsetcount
(
"
global
"
,
"
locationorder
"
,
lastorder
)
325
end
326 327 328
local
function
setnextinternal
(
kind
,
name
)
329
setnextorder
(
kind
,
name
)
-- always incremented with internal
330
local
n
=
texgetcount
(
"
locationcount
"
)
+
1
331
texsetcount
(
"
global
"
,
"
locationcount
"
,
n
)
332
return
n
333
end
334 335
local
function
currentorder
(
kind
,
name
)
336
return
orders
[
kind
]
and
orders
[
kind
]
[
name
]
or
lastorder
337
end
338 339
local
function
setcomponent
(
data
)
340
-- we might consider doing this at the tex end, just like prefix
341
local
component
=
productcomponent
(
)
342
if
component
then
343
local
references
=
data
and
data
.
references
344
if
references
then
345
references
.
component
=
component
346
if
references
.
prefix
=
=
component
then
347
references
.
prefix
=
nil
348
end
349
end
350
return
component
351
end
352
-- but for the moment we do it here (experiment)
353
end
354 355
references
.
setnextorder
=
setnextorder
356
references
.
setnextinternal
=
setnextinternal
357
references
.
currentorder
=
currentorder
358
references
.
setcomponent
=
setcomponent
359 360
implement
{
361
name
=
"
setnextreferenceorder
"
,
362
actions
=
setnextorder
,
363
arguments
=
"
2 strings
"
,
364
}
365 366
implement
{
367
name
=
"
setnextinternalreference
"
,
368
actions
=
setnextinternal
,
369
arguments
=
"
2 strings
"
,
370
}
371 372
implement
{
373
name
=
"
currentreferenceorder
"
,
374
actions
=
{
currentorder
,
context
}
,
375
arguments
=
"
2 strings
"
,
376
}
377 378
local
reported
=
setmetatableindex
(
"
table
"
)
379 380
function
references
.
set
(
data
)
381
local
references
=
data
.
references
382
local
reference
=
references
.
reference
383
if
not
reference
or
reference
=
=
"
"
then
384
-- report_references("invalid reference") -- harmless
385
return
0
386
end
387
local
prefix
=
references
.
prefix
or
"
"
388
local
pd
=
tobesaved
[
prefix
]
-- nicer is a metatable
389
if
not
pd
then
390
pd
=
{
}
391
tobesaved
[
prefix
]
=
pd
392
end
393
local
n
=
0
394
local
function
action
(
ref
)
395
if
ref
=
=
"
"
then
396
-- skip
397
elseif
check_duplicates
and
pd
[
ref
]
then
398
if
not
prefix
then
399
prefix
=
"
"
400
end
401
if
not
reported
[
prefix
]
[
ref
]
then
402
if
prefix
~
=
"
"
then
403
report_references
(
"
redundant reference %a in namespace %a
"
,
ref
,
prefix
)
404
else
405
report_references
(
"
redundant reference %a
"
,
ref
)
406
end
407
reported
[
prefix
]
[
ref
]
=
true
408
end
409
else
410
n
=
n
+
1
411
pd
[
ref
]
=
data
412
local
r
=
data
.
references
413
ctx_dofinishreference
(
prefix
or
"
"
,
ref
or
"
"
,
r
and
r
.
internal
or
0
)
414
-- ctx_latelua(function() structures.references.enhance(prefix or ref,ref or "") end)
415
end
416
end
417
process_settings
(
reference
,
action
)
418
return
n
>
0
419
end
420 421
-- function references.enhance(prefix,tag)
422
-- local l = tobesaved[prefix][tag]
423
-- if l then
424
-- l.references.realpage = texgetcount("realpageno")
425
-- end
426
-- end
427 428
local
function
synchronizepage
(
reference
)
-- non public helper
429
reference
.
realpage
=
texgetcount
(
"
realpageno
"
)
430
if
jobpositions
.
used
(
)
then
431
reference
.
x
,
reference
.
y
=
getpos
(
)
432
end
433
end
434 435
references
.
synchronizepage
=
synchronizepage
436 437
local
function
enhancereference
(
specification
)
438
local
l
=
tobesaved
[
specification
.
prefix
]
[
specification
.
tag
]
439
if
l
then
440
synchronizepage
(
l
.
references
)
441
end
442
end
443 444
references
.
enhance
=
enhancereference
445 446
-- implement {
447
-- name = "enhancereference",
448
-- arguments = "2 strings",
449
-- actions = function(prefix,tag)
450
-- enhancereference { prefix = prefix, tag = tag }
451
-- end,
452
-- }
453 454
implement
{
455
name
=
"
deferredenhancereference
"
,
456
arguments
=
"
2 strings
"
,
457
protected
=
true
,
458
actions
=
function
(
prefix
,
tag
)
459
ctx_latelua
{
action
=
enhancereference
,
prefix
=
prefix
,
tag
=
tag
}
460
end
,
461
}
462 463
-- -- -- related to strc-ini.lua -- -- --
464 465
-- no metatable here .. better be sparse
466 467
local
function
register_from_lists
(
collected
,
derived
,
pages
,
sections
)
468
local
derived_g
=
derived
[
"
"
]
-- global
469
local
derived_p
=
nil
470
local
derived_c
=
nil
471
local
prefix
=
nil
472
local
component
=
nil
473
local
entry
=
nil
474
if
not
derived_g
then
475
derived_g
=
{
}
476
derived
[
"
"
]
=
derived_g
477
end
478
local
function
action
(
s
)
479
if
trace_referencing
then
480
report_references
(
"
list entry %a provides %a reference %a on realpage %a
"
,
i
,
kind
,
s
,
realpage
)
481
end
482
if
derived_p
and
not
derived_p
[
s
]
then
483
derived_p
[
s
]
=
entry
484
end
485
if
derived_c
and
not
derived_c
[
s
]
then
486
derived_c
[
s
]
=
entry
487
end
488
if
not
derived_g
[
s
]
then
489
derived_g
[
s
]
=
entry
-- first wins
490
end
491
end
492
for
i
=
1
,
#
collected
do
493
entry
=
collected
[
i
]
494
local
metadata
=
entry
.
metadata
495
if
metadata
then
496
local
kind
=
metadata
.
kind
-- why this check
497
if
kind
then
498
local
references
=
entry
.
references
499
if
references
then
500
local
reference
=
references
.
reference
501
if
reference
and
reference
~
=
"
"
then
502
local
realpage
=
references
.
realpage
503
if
realpage
then
504
prefix
=
references
.
prefix
505
component
=
references
.
component
506
if
prefix
and
prefix
~
=
"
"
then
507
derived_p
=
derived
[
prefix
]
508
if
not
derived_p
then
509
derived_p
=
{
}
510
derived
[
prefix
]
=
derived_p
511
end
512
end
513
if
component
and
component
~
=
"
"
and
component
~
=
prefix
then
514
derived_c
=
derived
[
component
]
515
if
not
derived_c
then
516
derived_c
=
{
}
517
derived
[
component
]
=
derived_c
518
end
519
end
520
process_settings
(
reference
,
action
)
521
end
522
end
523
end
524
end
525
end
526
end
527
end
528 529
references
.
registerinitializer
(
function
(
)
register_from_lists
(
lists
.
collected
,
derived
)
end
)
530 531
-- tracing
532 533
local
function
collectbypage
(
tracedpages
)
534
-- lists
535
do
536
local
collected
=
structures
.
lists
.
collected
537
local
data
=
nil
538
local
function
action
(
reference
)
539
local
prefix
=
data
.
prefix
540
local
component
=
data
.
component
541
local
realpage
=
data
.
realpage
542
if
realpage
then
543
local
pagelist
=
rawget
(
tracedpages
,
realpage
)
544
local
internal
=
data
.
internal
or
0
545
local
prefix
=
(
prefix
~
=
"
"
and
prefix
)
or
(
component
~
=
"
"
and
component
)
or
"
"
546
local
pagedata
=
{
prefix
,
reference
,
internal
}
547
if
pagelist
then
548
pagelist
[
#
pagelist
+
1
]
=
pagedata
549
else
550
tracedpages
[
realpage
]
=
{
pagedata
}
551
end
552
if
internal
>
0
then
553
data
.
usedprefix
=
prefix
554
end
555
end
556
end
557
for
i
=
1
,
#
collected
do
558
local
entry
=
collected
[
i
]
559
local
metadata
=
entry
.
metadata
560
if
metadata
and
metadata
.
kind
then
561
data
=
entry
.
references
562
if
data
then
563
local
reference
=
data
.
reference
564
if
reference
and
reference
~
=
"
"
then
565
process_settings
(
reference
,
action
)
566
end
567
end
568
end
569
end
570
end
571
-- references
572
do
573
for
prefix
,
list
in
next
,
collected
do
574
for
reference
,
entry
in
next
,
list
do
575
local
data
=
entry
.
references
576
if
data
then
577
local
realpage
=
data
.
realpage
578
local
internal
=
data
.
internal
or
0
579
local
pagelist
=
rawget
(
tracedpages
,
realpage
)
580
local
pagedata
=
{
prefix
,
reference
,
internal
}
581
if
pagelist
then
582
pagelist
[
#
pagelist
+
1
]
=
pagedata
583
else
584
tracedpages
[
realpage
]
=
{
pagedata
}
585
end
586
if
internal
>
0
then
587
data
.
usedprefix
=
prefix
588
end
589
end
590
end
591
end
592
end
593
end
594 595
references
.
tracedpages
=
table
.
setmetatableindex
(
allocate
(
)
,
function
(
t
,
k
)
596
if
collectbypage
then
597
collectbypage
(
t
)
598
collectbypage
=
nil
599
end
600
return
rawget
(
t
,
k
)
601
end
)
602 603
-- urls
604 605
local
urls
=
references
.
urls
or
{
}
606
references
.
urls
=
urls
607
local
urldata
=
urls
.
data
or
{
}
608
urls
.
data
=
urldata
609 610
local
p_untexurl
=
Cs
(
(
611
P
(
"
\\
"
)
/
"
"
*
(
P
(
"
%
"
)
/
"
%%
"
+
P
(
1
)
)
612
+
P
(
"
"
)
/
"
%%20
"
613
+
P
(
1
)
614
)
^
1
)
615 616
function
urls
.
untex
(
url
)
617
return
lpegmatch
(
p_untexurl
,
url
)
or
url
618
end
619 620
function
urls
.
define
(
name
,
url
,
file
,
description
)
621
if
name
and
name
~
=
"
"
then
622
-- url = lpegmatch(replacer,url)
623
urldata
[
name
]
=
{
url
or
"
"
,
file
or
"
"
,
description
or
url
or
file
or
"
"
}
624
end
625
end
626 627
function
urls
.
get
(
name
)
628
local
u
=
urldata
[
name
]
629
if
u
then
630
local
url
,
file
=
u
[
1
]
,
u
[
2
]
631
if
file
and
file
~
=
"
"
then
632
return
formatters
[
"
%s/%s
"
]
(
url
,
file
)
633
else
634
return
url
635
end
636
end
637
end
638 639
function
urls
.
found
(
name
)
640
return
urldata
[
name
]
641
end
642 643
local
function
geturl
(
name
)
644
local
url
=
urls
.
get
(
name
)
645
if
url
and
url
~
=
"
"
then
646
ctx_pushcatcodes
(
txtcatcodes
)
647
context
(
url
)
648
ctx_popcatcodes
(
)
649
end
650
end
651 652
implement
{
653
name
=
"
doifelseurldefined
"
,
654
actions
=
{
urls
.
found
,
commands
.
doifelse
}
,
655
arguments
=
"
string
"
656
}
657 658
implement
{
659
name
=
"
useurl
"
,
660
actions
=
urls
.
define
,
661
arguments
=
"
4 strings
"
,
662
}
663 664
implement
{
665
name
=
"
geturl
"
,
666
actions
=
geturl
,
667
arguments
=
"
string
"
,
668
}
669 670
-- files
671 672
local
files
=
references
.
files
or
{
}
673
references
.
files
=
files
674
local
filedata
=
files
.
data
or
{
}
675
files
.
data
=
filedata
676 677
function
files
.
define
(
name
,
file
,
description
)
678
if
name
and
name
~
=
"
"
then
679
filedata
[
name
]
=
{
file
or
"
"
,
description
or
file
or
"
"
}
680
end
681
end
682 683
function
files
.
get
(
name
,
method
,
space
)
-- method: none, before, after, both, space: yes/no
684
local
f
=
filedata
[
name
]
685
if
f
then
686
context
(
f
[
1
]
)
687
end
688
end
689 690
function
files
.
found
(
name
)
691
return
filedata
[
name
]
692
end
693 694
local
function
getfile
(
name
)
695
local
fil
=
files
.
get
(
name
)
696
if
fil
and
fil
~
=
"
"
then
697
ctx_pushcatcodes
(
txtcatcodes
)
698
context
(
fil
)
699
ctx_popcatcodes
(
)
700
end
701
end
702 703
implement
{
704
name
=
"
doifelsefiledefined
"
,
705
actions
=
{
files
.
found
,
commands
.
doifelse
}
,
706
arguments
=
"
string
"
707
}
708 709
implement
{
710
name
=
"
usefile
"
,
711
actions
=
files
.
define
,
712
arguments
=
"
3 strings
"
713
}
714 715
implement
{
716
name
=
"
getfile
"
,
717
actions
=
getfile
,
718
arguments
=
"
string
"
719
}
720 721
-- helpers
722 723
function
references
.
checkedfile
(
whatever
)
-- return whatever if not resolved
724
if
whatever
then
725
local
w
=
filedata
[
whatever
]
726
if
w
then
727
return
w
[
1
]
728
else
729
return
whatever
730
end
731
end
732
end
733 734
function
references
.
checkedurl
(
whatever
)
-- return whatever if not resolved
735
if
whatever
then
736
local
w
=
urldata
[
whatever
]
737
if
w
then
738
local
u
,
f
=
w
[
1
]
,
w
[
2
]
739
if
f
and
f
~
=
"
"
then
740
return
u
.
.
"
/
"
.
.
f
741
else
742
return
u
743
end
744
else
745
return
whatever
746
end
747
end
748
end
749 750
function
references
.
checkedfileorurl
(
whatever
,
default
)
-- return nil, nil if not resolved
751
if
whatever
then
752
local
w
=
filedata
[
whatever
]
753
if
w
then
754
return
w
[
1
]
,
nil
755
else
756
local
w
=
urldata
[
whatever
]
757
if
w
then
758
local
u
,
f
=
w
[
1
]
,
w
[
2
]
759
if
f
and
f
~
=
"
"
then
760
return
nil
,
u
.
.
"
/
"
.
.
f
761
else
762
return
nil
,
u
763
end
764
end
765
end
766
end
767
return
default
768
end
769 770
-- programs
771 772
local
programs
=
references
.
programs
or
{
}
773
references
.
programs
=
programs
774
local
programdata
=
programs
.
data
or
{
}
775
programs
.
data
=
programdata
776 777
function
programs
.
define
(
name
,
file
,
description
)
778
if
name
and
name
~
=
"
"
then
779
programdata
[
name
]
=
{
file
or
"
"
,
description
or
file
or
"
"
}
780
end
781
end
782 783
function
programs
.
get
(
name
)
784
local
f
=
programdata
[
name
]
785
return
f
and
f
[
1
]
786
end
787 788
function
references
.
checkedprogram
(
whatever
)
-- return whatever if not resolved
789
if
whatever
then
790
local
w
=
programdata
[
whatever
]
791
if
w
then
792
return
w
[
1
]
793
else
794
return
whatever
795
end
796
end
797
end
798 799
implement
{
800
name
=
"
defineprogram
"
,
801
actions
=
programs
.
define
,
802
arguments
=
"
3 strings
"
,
803
}
804 805
local
function
getprogram
(
name
)
806
local
p
=
programdata
[
name
]
807
if
p
then
808
context
(
p
[
1
]
)
809
end
810
end
811 812
implement
{
813
name
=
"
getprogram
"
,
814
actions
=
getprogram
,
815
arguments
=
"
string
"
816
}
817 818
-- shared by urls and files
819 820
function
references
.
from
(
name
)
821
local
u
=
urldata
[
name
]
822
if
u
then
823
local
url
,
file
,
description
=
u
[
1
]
,
u
[
2
]
,
u
[
3
]
824
if
description
~
=
"
"
then
825
return
description
826
-- ok
827
elseif
file
and
file
~
=
"
"
then
828
return
url
.
.
"
/
"
.
.
file
829
else
830
return
url
831
end
832
else
833
local
f
=
filedata
[
name
]
834
if
f
then
835
local
file
,
description
=
f
[
1
]
,
f
[
2
]
836
if
description
~
=
"
"
then
837
return
description
838
else
839
return
file
840
end
841
end
842
end
843
end
844 845
local
function
from
(
name
)
846
local
u
=
urldata
[
name
]
847
if
u
then
848
local
url
,
file
,
description
=
u
[
1
]
,
u
[
2
]
,
u
[
3
]
849
if
description
~
=
"
"
then
850
ctx_dofromurldescription
(
description
)
851
-- ok
852
elseif
file
and
file
~
=
"
"
then
853
ctx_dofromurlliteral
(
url
.
.
"
/
"
.
.
file
)
854
else
855
ctx_dofromurlliteral
(
url
)
856
end
857
else
858
local
f
=
filedata
[
name
]
859
if
f
then
860
local
file
,
description
=
f
[
1
]
,
f
[
2
]
861
if
description
~
=
"
"
then
862
ctx_dofromfiledescription
(
description
)
863
else
864
ctx_dofromfileliteral
(
file
)
865
end
866
end
867
end
868
end
869 870
implement
{
871
name
=
"
from
"
,
872
actions
=
from
,
873
arguments
=
"
string
"
874
}
875 876
function
references
.
define
(
prefix
,
reference
,
list
)
877
local
d
=
defined
[
prefix
]
if
not
d
then
d
=
{
}
defined
[
prefix
]
=
d
end
878
d
[
reference
]
=
list
879
end
880 881
function
references
.
reset
(
prefix
,
reference
)
882
local
d
=
defined
[
prefix
]
883
if
d
then
884
d
[
reference
]
=
nil
885
end
886
end
887 888
implement
{
889
name
=
"
definereference
"
,
890
actions
=
references
.
define
,
891
arguments
=
"
3 strings
"
,
892
}
893 894
implement
{
895
name
=
"
resetreference
"
,
896
actions
=
references
.
reset
,
897
arguments
=
"
2 strings
"
,
898
}
899 900
setmetatableindex
(
defined
,
"
table
"
)
901 902
local
function
resolve
(
prefix
,
reference
,
args
,
set
)
-- we start with prefix,reference
903
if
reference
and
reference
~
=
"
"
then
904
if
not
set
then
905
set
=
{
prefix
=
prefix
,
reference
=
reference
}
906
else
907
if
not
set
.
reference
then
set
.
reference
=
reference
end
908
if
not
set
.
prefix
then
set
.
prefix
=
prefix
end
909
end
910
-- local r = settings_to_array(reference)
911
local
r
=
settings_to_table
(
reference
)
-- maybe option to honor () []
912
for
i
=
1
,
#
r
do
913
local
ri
=
r
[
i
]
914
local
d
=
defined
[
prefix
]
[
ri
]
or
defined
[
"
"
]
[
ri
]
915
if
d
then
916
resolve
(
prefix
,
d
,
nil
,
set
)
917
else
918
local
var
=
splitreference
(
ri
)
919
if
var
then
920
var
.
reference
=
ri
921
local
vo
,
vi
=
var
.
outer
,
var
.
inner
922
-- we catch this here .. it's a way to pass references with commas
923
if
vi
=
=
"
name
"
then
924
local
arguments
=
var
.
arguments
925
if
arguments
then
926
vi
=
arguments
927
var
.
inner
=
arguments
928
var
.
reference
=
arguments
929
var
.
arguments
=
nil
930
end
931
elseif
var
.
special
=
=
"
name
"
then
932
local
operation
=
var
.
operation
933
if
operation
then
934
vi
=
operation
935
var
.
inner
=
operation
936
var
.
reference
=
operation
937
var
.
operation
=
nil
938
var
.
special
=
nil
939
end
940
end
941
-- end of catch
942
if
not
vo
and
vi
then
943
-- to be checked
944
d
=
defined
[
prefix
]
[
vi
]
or
defined
[
"
"
]
[
vi
]
945
--
946
if
d
then
947
resolve
(
prefix
,
d
,
var
.
arguments
,
set
)
-- args can be nil
948
else
949
if
args
then
var
.
arguments
=
args
end
950
set
[
#
set
+
1
]
=
var
951
end
952
else
953
if
args
then
var
.
arguments
=
args
end
954
set
[
#
set
+
1
]
=
var
955
end
956
if
var
.
has_tex
then
957
set
.
has_tex
=
true
958
end
959
else
960
-- report_references("funny pattern %a",ri)
961
end
962
end
963
end
964
return
set
965
else
966
return
{
}
967
end
968
end
969 970
-- prefix == "" is valid prefix which saves multistep lookup
971 972
references
.
currentset
=
nil
973 974
local
function
setreferenceoperation
(
k
,
v
)
975
references
.
currentset
[
k
]
.
operation
=
v
976
end
977 978
local
function
setreferencearguments
(
k
,
v
)
979
references
.
currentset
[
k
]
.
arguments
=
v
980
end
981 982
function
references
.
expandcurrent
(
)
-- todo: two booleans: o_has_tex& a_has_tex
983
local
currentset
=
references
.
currentset
984
if
currentset
and
currentset
.
has_tex
then
985
for
i
=
1
,
#
currentset
do
986
local
ci
=
currentset
[
i
]
987
local
operation
=
ci
.
operation
988
if
operation
and
find
(
operation
,
"
\\
"
,
1
,
true
)
then
-- if o_has_tex then
989
ctx_expandreferenceoperation
(
i
,
operation
)
990
end
991
local
arguments
=
ci
.
arguments
992
if
arguments
and
find
(
arguments
,
"
\\
"
,
1
,
true
)
then
-- if a_has_tex then
993
ctx_expandreferencearguments
(
i
,
arguments
)
994
end
995
end
996
end
997
end
998 999
implement
{
1000
name
=
"
expandcurrentreference
"
,
1001
actions
=
references
.
expandcurrent
1002
}
1003 1004
implement
{
1005
name
=
"
setreferenceoperation
"
,
1006
actions
=
setreferenceoperation
,
1007
arguments
=
{
"
integer
"
,
"
string
"
}
1008
}
1009 1010
implement
{
1011
name
=
"
setreferencearguments
"
,
1012
actions
=
setreferencearguments
,
1013
arguments
=
{
"
integer
"
,
"
string
"
}
1014
}
1015 1016
local
externals
=
{
}
1017 1018
-- we have prefixes but also components:
1019
--
1020
-- : prefix
1021
-- :: always external
1022
-- ::: internal (for products) or external (for components)
1023 1024
local
function
loadexternalreferences
(
name
,
utilitydata
)
1025
local
struc
=
utilitydata
.
structures
1026
if
struc
then
1027
local
external
=
struc
.
references
.
collected
-- direct references
1028
local
lists
=
struc
.
lists
.
collected
-- indirect references (derived)
1029
local
pages
=
struc
.
pages
.
collected
-- pagenumber data
1030
-- a bit weird one, as we don't have the externals in the collected
1031
for
prefix
,
set
in
next
,
external
do
1032
if
prefix
=
=
"
"
then
1033
prefix
=
name
-- this can clash!
1034
end
1035
for
reference
,
data
in
next
,
set
do
1036
if
trace_importing
then
1037
report_importing
(
"
registering %a reference, kind %a, name %a, prefix %a, reference %a
"
,
1038
"
external
"
,
"
regular
"
,
name
,
prefix
,
reference
)
1039
end
1040
local
section
=
reference
.
section
1041
local
realpage
=
reference
.
realpage
1042
if
section
then
1043
reference
.
sectiondata
=
lists
[
section
]
1044
end
1045
if
realpage
then
1046
reference
.
pagedata
=
pages
[
realpage
]
1047
end
1048
end
1049
end
1050
for
i
=
1
,
#
lists
do
1051
local
entry
=
lists
[
i
]
1052
local
metadata
=
entry
.
metadata
1053
local
references
=
entry
.
references
1054
if
metadata
and
references
then
1055
local
reference
=
references
.
reference
1056
if
reference
and
reference
~
=
"
"
then
1057
local
kind
=
metadata
.
kind
1058
local
realpage
=
references
.
realpage
1059
if
kind
and
realpage
then
1060
references
.
pagedata
=
pages
[
realpage
]
1061
local
prefix
=
references
.
prefix
or
"
"
1062
if
prefix
=
=
"
"
then
1063
prefix
=
name
-- this can clash!
1064
end
1065
local
target
=
external
[
prefix
]
1066
if
not
target
then
1067
target
=
{
}
1068
external
[
prefix
]
=
target
1069
end
1070
-- for s in gmatch(reference,"%s*([^,]+)") do
1071
-- if trace_importing then
1072
-- report_importing("registering %s reference, kind %a, name %a, prefix %a, reference %a",
1073
-- "external",kind,name,prefix,s)
1074
-- end
1075
-- target[s] = target[s] or entry
1076
-- end
1077
local
function
action
(
s
)
1078
if
trace_importing
then
1079
report_importing
(
"
registering %s reference, kind %a, name %a, prefix %a, reference %a
"
,
1080
"
external
"
,
kind
,
name
,
prefix
,
s
)
1081
end
1082
target
[
s
]
=
target
[
s
]
or
entry
1083
end
1084
process_settings
(
reference
,
action
)
1085
end
1086
end
1087
end
1088
end
1089
externals
[
name
]
=
external
1090
return
external
1091
end
1092
end
1093 1094
local
externalfiles
=
{
}
1095 1096
setmetatableindex
(
externalfiles
,
function
(
t
,
k
)
1097
local
v
=
filedata
[
k
]
1098
if
not
v
then
1099
v
=
{
k
,
k
}
1100
end
1101
externalfiles
[
k
]
=
v
1102
return
v
1103
end
)
1104 1105
setmetatableindex
(
externals
,
function
(
t
,
k
)
-- either or not automatically
1106
local
filename
=
externalfiles
[
k
]
[
1
]
-- filename
1107
local
fullname
=
file
.
replacesuffix
(
filename
,
"
tuc
"
)
1108
if
lfs
.
isfile
(
fullname
)
then
-- todo: use other locator
1109
local
utilitydata
=
job
.
loadother
(
fullname
)
1110
if
utilitydata
then
1111
local
external
=
loadexternalreferences
(
k
,
utilitydata
)
1112
t
[
k
]
=
external
or
false
1113
return
external
1114
end
1115
end
1116
t
[
k
]
=
false
1117
return
false
1118
end
)
1119 1120
local
productdata
=
allocate
{
1121
productreferences
=
{
}
,
1122
componentreferences
=
{
}
,
1123
components
=
{
}
,
1124
}
1125 1126
references
.
productdata
=
productdata
1127 1128
local
function
loadproductreferences
(
productname
,
componentname
,
utilitydata
)
1129
local
struc
=
utilitydata
.
structures
1130
if
struc
then
1131
local
productreferences
=
struc
.
references
.
collected
-- direct references
1132
local
lists
=
struc
.
lists
.
collected
-- indirect references (derived)
1133
local
pages
=
struc
.
pages
.
collected
-- pagenumber data
1134
-- we use indirect tables to save room but as they are eventually
1135
-- just references we resolve them to data here (the mechanisms
1136
-- that use this data check for indirectness)
1137
for
prefix
,
set
in
next
,
productreferences
do
1138
for
reference
,
data
in
next
,
set
do
1139
if
trace_importing
then
1140
report_importing
(
"
registering %s reference, kind %a, name %a, prefix %a, reference %a
"
,
1141
"
product
"
,
"
regular
"
,
productname
,
prefix
,
reference
)
1142
end
1143
local
section
=
reference
.
section
1144
local
realpage
=
reference
.
realpage
1145
if
section
then
1146
reference
.
sectiondata
=
lists
[
section
]
1147
end
1148
if
realpage
then
1149
reference
.
pagedata
=
pages
[
realpage
]
1150
end
1151
end
1152
end
1153
--
1154
local
componentreferences
=
{
}
1155
for
i
=
1
,
#
lists
do
1156
local
entry
=
lists
[
i
]
1157
local
metadata
=
entry
.
metadata
1158
local
references
=
entry
.
references
1159
if
metadata
and
references
then
1160
local
reference
=
references
.
reference
1161
if
reference
and
reference
~
=
"
"
then
1162
local
kind
=
metadata
.
kind
1163
local
realpage
=
references
.
realpage
1164
if
kind
and
realpage
then
1165
references
.
pagedata
=
pages
[
realpage
]
1166
local
prefix
=
references
.
prefix
or
"
"
1167
local
component
=
references
.
component
1168
local
ctarget
,
ptarget
1169
if
not
component
or
component
=
=
componentname
then
1170
-- skip
1171
else
1172
-- one level up
1173
local
external
=
componentreferences
[
component
]
1174
if
not
external
then
1175
external
=
{
}
1176
componentreferences
[
component
]
=
external
1177
end
1178
if
component
=
=
prefix
then
1179
prefix
=
"
"
1180
end
1181
ctarget
=
external
[
prefix
]
1182
if
not
ctarget
then
1183
ctarget
=
{
}
1184
external
[
prefix
]
=
ctarget
1185
end
1186
end
1187
ptarget
=
productreferences
[
prefix
]
1188
if
not
ptarget
then
1189
ptarget
=
{
}
1190
productreferences
[
prefix
]
=
ptarget
1191
end
1192
local
function
action
(
s
)
1193
if
ptarget
then
1194
if
trace_importing
then
1195
report_importing
(
"
registering %s reference, kind %a, name %a, prefix %a, reference %a
"
,
1196
"
product
"
,
kind
,
productname
,
prefix
,
s
)
1197
end
1198
ptarget
[
s
]
=
ptarget
[
s
]
or
entry
1199
end
1200
if
ctarget
then
1201
if
trace_importing
then
1202
report_importing
(
"
registering %s reference, kind %a, name %a, prefix %a, referenc %a
"
,
1203
"
component
"
,
kind
,
productname
,
prefix
,
s
)
1204
end
1205
ctarget
[
s
]
=
ctarget
[
s
]
or
entry
1206
end
1207
end
1208
process_settings
(
reference
,
action
)
1209
end
1210
end
1211
end
1212
end
1213
productdata
.
productreferences
=
productreferences
-- not yet used
1214
productdata
.
componentreferences
=
componentreferences
1215
end
1216
end
1217 1218
local
function
loadproductvariables
(
product
,
component
,
utilitydata
)
1219
local
struc
=
utilitydata
.
structures
1220
if
struc
then
1221
local
lists
=
struc
.
lists
and
struc
.
lists
.
collected
1222
if
lists
then
1223
local
pages
=
struc
.
pages
and
struc
.
pages
.
collected
1224
for
i
=
1
,
#
lists
do
1225
local
li
=
lists
[
i
]
1226
if
li
.
metadata
.
kind
=
=
"
section
"
and
li
.
references
.
component
=
=
component
then
1227
local
firstsection
=
li
1228
if
firstsection
.
numberdata
then
1229
local
numbers
=
firstsection
.
numberdata
.
numbers
1230
if
numbers
then
1231
if
trace_importing
then
1232
report_importing
(
"
initializing section number to %:t
"
,
numbers
)
1233
end
1234
productdata
.
firstsection
=
firstsection
1235
structures
.
documents
.
preset
(
numbers
)
1236
end
1237
end
1238
if
pages
and
firstsection
.
references
then
1239
local
firstpage
=
pages
[
firstsection
.
references
.
realpage
]
1240
local
number
=
firstpage
and
firstpage
.
number
1241
if
number
then
1242
if
trace_importing
then
1243
report_importing
(
"
initializing page number to %a
"
,
number
)
1244
end
1245
productdata
.
firstpage
=
firstpage
1246
counters
.
set
(
"
userpage
"
,
1
,
number
)
1247
end
1248
end
1249
break
1250
end
1251
end
1252
end
1253
end
1254
end
1255 1256
local
function
componentlist
(
tree
,
target
)
1257
local
branches
=
tree
and
tree
.
branches
1258
if
branches
then
1259
for
i
=
1
,
#
branches
do
1260
local
branch
=
branches
[
i
]
1261
local
type
=
branch
.
type
1262
if
type
=
=
"
component
"
then
1263
if
target
then
1264
target
[
#
target
+
1
]
=
branch
.
name
1265
else
1266
target
=
{
branch
.
name
}
1267
end
1268
elseif
type
=
=
"
product
"
or
type
=
=
"
component
"
then
1269
target
=
componentlist
(
branch
,
target
)
1270
end
1271
end
1272
end
1273
return
target
1274
end
1275 1276
local
function
loadproductcomponents
(
product
,
component
,
utilitydata
)
1277
local
job
=
utilitydata
.
job
1278
productdata
.
components
=
componentlist
(
job
and
job
.
structure
and
job
.
structure
.
collected
)
or
{
}
1279
end
1280 1281
references
.
registerinitializer
(
function
(
tobesaved
,
collected
)
1282
-- not that much related to tobesaved or collected
1283
productdata
.
components
=
componentlist
(
job
.
structure
.
collected
)
or
{
}
1284
end
)
1285 1286
function
references
.
loadpresets
(
product
,
component
)
-- we can consider a special components hash
1287
if
product
and
component
and
product
~
=
"
"
and
component
~
=
"
"
and
not
productdata
.
product
then
-- maybe: productdata.filename ~= filename
1288
productdata
.
product
=
product
1289
productdata
.
component
=
component
1290
local
fullname
=
file
.
replacesuffix
(
product
,
"
tuc
"
)
1291
if
lfs
.
isfile
(
fullname
)
then
-- todo: use other locator
1292
local
utilitydata
=
job
.
loadother
(
fullname
)
1293
if
utilitydata
then
1294
if
trace_importing
then
1295
report_importing
(
"
loading references for component %a of product %a from %a
"
,
component
,
product
,
fullname
)
1296
end
1297
loadproductvariables
(
product
,
component
,
utilitydata
)
1298
loadproductreferences
(
product
,
component
,
utilitydata
)
1299
loadproductcomponents
(
product
,
component
,
utilitydata
)
1300
end
1301
end
1302
end
1303
end
1304 1305
references
.
productdata
=
productdata
1306 1307
local
useproduct
=
commands
.
useproduct
1308 1309
if
useproduct
then
1310 1311
local
function
newuseproduct
(
product
)
1312
useproduct
(
product
)
1313
if
texconditionals
.
autocrossfilereferences
then
1314
local
component
=
justacomponent
(
)
1315
if
component
then
1316
if
trace_referencing
or
trace_importing
then
1317
report_references
(
"
loading presets for component %a of product %a
"
,
component
,
product
)
1318
end
1319
references
.
loadpresets
(
product
,
component
)
1320
end
1321
end
1322
end
1323 1324
implement
{
1325
name
=
"
useproduct
"
,
1326
actions
=
newuseproduct
,
1327
arguments
=
"
string
"
,
1328
overload
=
true
,
1329
}
1330 1331
end
1332 1333
-- productdata.firstsection.numberdata.numbers
1334
-- productdata.firstpage.number
1335 1336
local
function
report_identify_special
(
set
,
var
,
i
,
type
)
1337
local
reference
=
set
.
reference
1338
local
prefix
=
set
.
prefix
or
"
"
1339
local
special
=
var
.
special
1340
local
error
=
var
.
error
1341
local
kind
=
var
.
kind
1342
if
error
then
1343
report_identifying
(
"
type %a, reference %a, index %a, prefix %a, special %a, error %a
"
,
type
,
reference
,
i
,
prefix
,
special
,
error
)
1344
else
1345
report_identifying
(
"
type %a, reference %a, index %a, prefix %a, special %a, kind %a
"
,
type
,
reference
,
i
,
prefix
,
special
,
kind
)
1346
end
1347
end
1348 1349
local
function
report_identify_arguments
(
set
,
var
,
i
,
type
)
1350
local
reference
=
set
.
reference
1351
local
prefix
=
set
.
prefix
or
"
"
1352
local
arguments
=
var
.
arguments
1353
local
error
=
var
.
error
1354
local
kind
=
var
.
kind
1355
if
error
then
1356
report_identifying
(
"
type %a, reference %a, index %a, prefix %a, arguments %a, error %a
"
,
type
,
reference
,
i
,
prefix
,
arguments
,
error
)
1357
else
1358
report_identifying
(
"
type %a, reference %a, index %a, prefix %a, arguments %a, kind %a
"
,
type
,
reference
,
i
,
prefix
,
arguments
,
kind
)
1359
end
1360
end
1361 1362
local
function
report_identify_outer
(
set
,
var
,
i
,
type
)
1363
local
reference
=
set
.
reference
1364
local
prefix
=
set
.
prefix
or
"
"
1365
local
outer
=
var
.
outer
1366
local
error
=
var
.
error
1367
local
kind
=
var
.
kind
1368
if
outer
then
1369
if
error
then
1370
report_identifying
(
"
type %a, reference %a, index %a, prefix %a, outer %a, error %a
"
,
type
,
reference
,
i
,
prefix
,
outer
,
error
)
1371
else
1372
report_identifying
(
"
type %a, reference %a, index %a, prefix %a, outer %a, kind %a
"
,
type
,
reference
,
i
,
prefix
,
outer
,
kind
)
1373
end
1374
else
1375
if
error
then
1376
report_identifying
(
"
type %a, reference %a, index %a, prefix %a, error %a
"
,
type
,
reference
,
i
,
prefix
,
error
)
1377
else
1378
report_identifying
(
"
type %a, reference %a, index %a, prefix %a, kind %a
"
,
type
,
reference
,
i
,
prefix
,
kind
)
1379
end
1380
end
1381
end
1382 1383
local
function
identify_special
(
set
,
var
,
i
)
1384
local
special
=
var
.
special
1385
local
s
=
specials
[
special
]
1386
if
s
then
1387
local
outer
=
var
.
outer
1388
local
operation
=
var
.
operation
1389
local
arguments
=
var
.
arguments
1390
if
outer
then
1391
if
operation
then
1392
-- special(outer::operation)
1393
var
.
kind
=
"
special outer with operation
"
1394
else
1395
-- special()
1396
var
.
kind
=
"
special outer
"
1397
end
1398
var
.
f
=
outer
1399
elseif
operation
then
1400
if
arguments
then
1401
-- special(operation{argument,argument})
1402
var
.
kind
=
"
special operation with arguments
"
1403
else
1404
-- special(operation)
1405
var
.
kind
=
"
special operation
"
1406
end
1407
else
1408
-- special()
1409
var
.
kind
=
"
special
"
1410
end
1411
if
trace_identifying
then
1412
report_identify_special
(
set
,
var
,
i
,
"
1a
"
)
1413
end
1414
else
1415
var
.
error
=
"
unknown special
"
1416
end
1417
return
var
1418
end
1419 1420
local
function
identify_arguments
(
set
,
var
,
i
)
1421
local
s
=
specials
[
var
.
inner
]
1422
if
s
then
1423
-- inner{argument}
1424
var
.
kind
=
"
special operation with arguments
"
1425
else
1426
var
.
error
=
"
unknown inner or special
"
1427
end
1428
if
trace_identifying
then
1429
report_identify_arguments
(
set
,
var
,
i
,
"
3a
"
)
1430
end
1431
return
var
1432
end
1433 1434
-- needs checking: if we don't do too much (redundant) checking now
1435
-- inner ... we could move the prefix logic into the parser so that we have 'm for each entry
1436
-- foo:bar -> foo == prefix (first we try the global one)
1437
-- -:bar -> ignore prefix
1438 1439
local
function
finish_inner
(
var
,
p
,
i
)
1440
var
.
kind
=
"
inner
"
1441
var
.
i
=
i
1442
var
.
p
=
p
1443
var
.
r
=
(
i
.
references
and
i
.
references
.
realpage
)
or
(
i
.
pagedata
and
i
.
pagedata
.
realpage
)
or
1
1444
return
var
1445
end
1446 1447
local
function
identify_inner
(
set
,
var
,
prefix
,
collected
,
derived
)
1448
local
inner
=
var
.
inner
1449
-- the next test is a safeguard when references are auto loaded from outer
1450
if
not
inner
or
inner
=
=
"
"
then
1451
return
false
1452
end
1453
local
splitprefix
,
splitinner
=
lpegmatch
(
prefixsplitter
,
inner
)
1454
if
splitprefix
and
splitinner
then
1455
-- we check for a prefix:reference instance in the regular set of collected
1456
-- references; a special case is -: which forces a lookup in the global list
1457
if
splitprefix
=
=
"
-
"
then
1458
local
i
=
collected
[
"
"
]
1459
if
i
then
1460
i
=
i
[
splitinner
]
1461
if
i
then
1462
return
finish_inner
(
var
,
"
"
,
i
)
1463
end
1464
end
1465
end
1466
local
i
=
collected
[
splitprefix
]
1467
if
i
then
1468
i
=
i
[
splitinner
]
1469
if
i
then
1470
return
finish_inner
(
var
,
splitprefix
,
i
)
1471
end
1472
end
1473
if
derived
then
1474
-- next we look for a reference in the regular set of collected references
1475
-- using the prefix that is active at this moment (so we overload the given
1476
-- these are taken from other data structures (like lists)
1477
if
splitprefix
=
=
"
-
"
then
1478
local
i
=
derived
[
"
"
]
1479
if
i
then
1480
i
=
i
[
splitinner
]
1481
if
i
then
1482
return
finish_inner
(
var
,
"
"
,
i
)
1483
end
1484
end
1485
end
1486
local
i
=
derived
[
splitprefix
]
1487
if
i
then
1488
i
=
i
[
splitinner
]
1489
if
i
then
1490
return
finish_inner
(
var
,
splitprefix
,
i
)
1491
end
1492
end
1493
end
1494
end
1495
-- we now ignore the split prefix and treat the whole inner as a potential
1496
-- reference into the global list
1497
local
i
=
collected
[
prefix
]
1498
if
i
then
1499
i
=
i
[
inner
]
1500
if
i
then
1501
return
finish_inner
(
var
,
prefix
,
i
)
1502
end
1503
end
1504
if
not
i
and
derived
then
1505
-- and if not found we look in the derived references
1506
local
i
=
derived
[
prefix
]
1507
if
i
then
1508
i
=
i
[
inner
]
1509
if
i
then
1510
return
finish_inner
(
var
,
prefix
,
i
)
1511
end
1512
end
1513
end
1514
return
false
1515
end
1516 1517
local
function
unprefixed_inner
(
set
,
var
,
prefix
,
collected
,
derived
,
tobesaved
)
1518
local
inner
=
var
.
inner
1519
local
s
=
specials
[
inner
]
1520
if
s
then
1521
var
.
kind
=
"
special
"
1522
else
1523
local
i
=
(
collected
and
collected
[
"
"
]
and
collected
[
"
"
]
[
inner
]
)
or
1524
(
derived
and
derived
[
"
"
]
and
derived
[
"
"
]
[
inner
]
)
or
1525
(
tobesaved
and
tobesaved
[
"
"
]
and
tobesaved
[
"
"
]
[
inner
]
)
1526
if
i
then
1527
var
.
kind
=
"
inner
"
1528
var
.
p
=
"
"
1529
var
.
i
=
i
1530
var
.
r
=
(
i
.
references
and
i
.
references
.
realpage
)
or
(
i
.
pagedata
and
i
.
pagedata
.
realpage
)
or
1
1531
else
1532
var
.
error
=
"
unknown inner or special
"
1533
end
1534
end
1535
return
var
1536
end
1537 1538
local
function
identify_outer
(
set
,
var
,
i
)
1539
local
outer
=
var
.
outer
1540
local
inner
=
var
.
inner
1541
local
external
=
externals
[
outer
]
1542
if
external
then
1543
local
v
=
identify_inner
(
set
,
var
,
"
"
,
external
)
1544
if
v
then
1545
v
.
kind
=
"
outer with inner
"
1546
set
.
external
=
true
1547
if
trace_identifying
then
1548
report_identify_outer
(
set
,
v
,
i
,
"
2a
"
)
1549
end
1550
return
v
1551
end
1552
-- weird too (we really need to check how this table is build
1553
local
v
=
identify_inner
(
set
,
var
,
var
.
outer
,
external
)
1554
if
v
then
1555
v
.
kind
=
"
outer with inner
"
1556
set
.
external
=
true
1557
if
trace_identifying
then
1558
report_identify_outer
(
set
,
v
,
i
,
"
2c
"
)
1559
end
1560
return
v
1561
end
1562
--
1563
-- somewhat rubish: we use outer as first step in the externals table so it makes no
1564
-- sense to have it as prefix so the next could be an option
1565
local
external
=
external
[
"
"
]
1566
if
external
then
1567
local
v
=
identify_inner
(
set
,
var
,
var
.
outer
,
external
)
1568
if
v
then
1569
v
.
kind
=
"
outer with inner
"
1570
set
.
external
=
true
1571
if
trace_identifying
then
1572
report_identify_outer
(
set
,
v
,
i
,
"
2b
"
)
1573
end
1574
return
v
1575
end
1576
end
1577
end
1578
local
external
=
productdata
.
componentreferences
[
outer
]
1579
if
external
then
1580
local
v
=
identify_inner
(
set
,
var
,
"
"
,
external
)
1581
if
v
then
1582
v
.
kind
=
"
outer with inner
"
1583
set
.
external
=
true
1584
if
trace_identifying
then
1585
report_identify_outer
(
set
,
v
,
i
,
"
2c
"
)
1586
end
1587
return
v
1588
end
1589
end
1590
local
external
=
productdata
.
productreferences
[
outer
]
1591
if
external
then
1592
local
vi
=
external
[
inner
]
1593
if
vi
then
1594
var
.
kind
=
"
outer with inner
"
1595
var
.
i
=
vi
1596
set
.
external
=
true
1597
if
trace_identifying
then
1598
report_identify_outer
(
set
,
var
,
i
,
"
2d
"
)
1599
end
1600
return
var
1601
end
1602
end
1603
-- the rest
1604
local
special
=
var
.
special
1605
local
arguments
=
var
.
arguments
1606
local
operation
=
var
.
operation
1607
if
inner
then
1608
-- tricky: in this case we can only use views when we're sure that all inners
1609
-- are flushed in the outer document so that should become an option
1610
if
arguments
then
1611
-- outer::inner{argument}
1612
var
.
kind
=
"
outer with inner with arguments
"
1613
else
1614
-- outer::inner
1615
var
.
kind
=
"
outer with inner
"
1616
end
1617
var
.
i
=
inner
1618
var
.
f
=
outer
1619
if
type
(
inner
)
=
=
"
table
"
then
1620
-- can this really happen?
1621
var
.
r
=
(
inner
.
references
and
inner
.
references
.
realpage
)
or
(
inner
.
pagedata
and
inner
.
pagedata
.
realpage
)
or
1
1622
else
1623
var
.
r
=
1
1624
end
1625
if
trace_identifying
then
1626
report_identify_outer
(
set
,
var
,
i
,
"
2e
"
)
1627
end
1628
elseif
special
then
1629
local
s
=
specials
[
special
]
1630
if
s
then
1631
if
operation
then
1632
if
arguments
then
1633
-- outer::special(operation{argument,argument})
1634
var
.
kind
=
"
outer with special and operation and arguments
"
1635
else
1636
-- outer::special(operation)
1637
var
.
kind
=
"
outer with special and operation
"
1638
end
1639
else
1640
-- outer::special()
1641
var
.
kind
=
"
outer with special
"
1642
end
1643
var
.
f
=
outer
1644
else
1645
var
.
error
=
"
unknown outer with special
"
1646
end
1647
if
trace_identifying
then
1648
report_identify_outer
(
set
,
var
,
i
,
"
2f
"
)
1649
end
1650
else
1651
-- outer::
1652
var
.
kind
=
"
outer
"
1653
var
.
f
=
outer
1654
if
trace_identifying
then
1655
report_identify_outer
(
set
,
var
,
i
,
"
2g
"
)
1656
end
1657
end
1658
return
var
1659
end
1660 1661
-- todo: avoid copy
1662 1663
local
function
identify_inner_or_outer
(
set
,
var
,
i
)
1664
-- here we fall back on product data
1665
local
inner
=
var
.
inner
1666
if
inner
and
inner
~
=
"
"
then
1667 1668
-- first we look up in collected and derived using the current prefix
1669 1670
local
prefix
=
set
.
prefix
1671 1672
local
v
=
identify_inner
(
set
,
var
,
set
.
prefix
,
collected
,
derived
)
1673
if
v
then
1674
if
trace_identifying
then
1675
report_identify_outer
(
set
,
v
,
i
,
"
4a
"
)
1676
end
1677
return
v
1678
end
1679 1680
-- nest we look at each component (but we can omit the already consulted one
1681 1682
local
jobstructure
=
job
.
structure
1683
local
components
=
jobstructure
and
jobstructure
.
components
1684
if
components
then
1685
for
c
=
1
,
#
components
do
1686
local
component
=
components
[
c
]
1687
if
component
~
=
prefix
then
1688
local
v
=
identify_inner
(
set
,
var
,
component
,
collected
,
derived
)
1689
if
v
then
1690
if
trace_identifying
then
1691
report_identify_outer
(
set
,
var
,
i
,
"
4b
"
)
1692
end
1693
return
v
1694
end
1695
end
1696
end
1697
end
1698 1699
-- as a last resort we will consult the global lists
1700 1701
local
v
=
unprefixed_inner
(
set
,
var
,
"
"
,
collected
,
derived
,
tobesaved
)
1702
if
v
then
1703
if
trace_identifying
then
1704
report_identify_outer
(
set
,
v
,
i
,
"
4c
"
)
1705
end
1706
return
v
1707
end
1708 1709
-- not it gets bad ... we need to look in external files ... keep in mind that
1710
-- we can best use explicit references for this ... we might issue a warning
1711 1712
local
componentreferences
=
productdata
.
componentreferences
1713
local
productreferences
=
productdata
.
productreferences
1714
local
components
=
productdata
.
components
1715
if
components
and
componentreferences
then
1716
for
c
=
1
,
#
components
do
1717
local
component
=
components
[
c
]
1718
local
data
=
componentreferences
[
component
]
1719
if
data
then
1720
local
d
=
data
[
"
"
]
1721
local
vi
=
d
and
d
[
inner
]
1722
if
vi
then
1723
var
.
outer
=
component
1724
var
.
i
=
vi
1725
var
.
kind
=
"
outer with inner
"
1726
set
.
external
=
true
1727
if
trace_identifying
then
1728
report_identify_outer
(
set
,
var
,
i
,
"
4d
"
)
1729
end
1730
return
var
1731
end
1732
end
1733
end
1734
end
1735
local
component
,
inner
=
lpegmatch
(
componentsplitter
,
inner
)
1736
if
component
then
1737
local
data
=
componentreferences
and
componentreferences
[
component
]
1738
if
data
then
1739
local
d
=
data
[
"
"
]
1740
local
vi
=
d
and
d
[
inner
]
1741
if
vi
then
1742
var
.
inner
=
inner
1743
var
.
outer
=
component
1744
var
.
i
=
vi
1745
var
.
kind
=
"
outer with inner
"
1746
set
.
external
=
true
1747
if
trace_identifying
then
1748
report_identify_outer
(
set
,
var
,
i
,
"
4e
"
)
1749
end
1750
return
var
1751
end
1752
end
1753
local
data
=
productreferences
and
productreferences
[
component
]
1754
if
data
then
1755
local
vi
=
data
[
inner
]
1756
if
vi
then
1757
var
.
inner
=
inner
1758
var
.
outer
=
component
1759
var
.
i
=
vi
1760
var
.
kind
=
"
outer with inner
"
1761
set
.
external
=
true
1762
if
trace_identifying
then
1763
report_identify_outer
(
set
,
var
,
i
,
"
4f
"
)
1764
end
1765
return
var
1766
end
1767
end
1768
end
1769
var
.
error
=
"
unknown inner
"
1770
else
1771
var
.
error
=
"
no inner
"
1772
end
1773
if
trace_identifying
then
1774
report_identify_outer
(
set
,
var
,
i
,
"
4g
"
)
1775
end
1776
return
var
1777
end
1778 1779
local
function
identify_inner_component
(
set
,
var
,
i
)
1780
-- we're in a product (maybe ignore when same as component)
1781
local
component
=
var
.
component
1782
local
v
=
identify_inner
(
set
,
var
,
component
,
collected
,
derived
)
1783
if
not
v
then
1784
var
.
error
=
"
unknown inner in component
"
1785
end
1786
if
trace_identifying
then
1787
report_identify_outer
(
set
,
var
,
i
,
"
5a
"
)
1788
end
1789
return
var
1790
end
1791 1792
local
function
identify_outer_component
(
set
,
var
,
i
)
1793
local
component
=
var
.
component
1794
local
inner
=
var
.
inner
1795
local
data
=
productdata
.
componentreferences
[
component
]
1796
if
data
then
1797
local
d
=
data
[
"
"
]
1798
local
vi
=
d
and
d
[
inner
]
1799
if
vi
then
1800
var
.
inner
=
inner
1801
var
.
outer
=
component
1802
var
.
i
=
vi
1803
var
.
kind
=
"
outer with inner
"
1804
set
.
external
=
true
1805
if
trace_identifying
then
1806
report_identify_outer
(
set
,
var
,
i
,
"
6a
"
)
1807
end
1808
return
var
1809
end
1810
end
1811
local
data
=
productdata
.
productreferences
[
component
]
1812
if
data
then
1813
local
vi
=
data
[
inner
]
1814
if
vi
then
1815
var
.
inner
=
inner
1816
var
.
outer
=
component
1817
var
.
i
=
vi
1818
var
.
kind
=
"
outer with inner
"
1819
set
.
external
=
true
1820
if
trace_identifying
then
1821
report_identify_outer
(
set
,
var
,
i
,
"
6b
"
)
1822
end
1823
return
var
1824
end
1825
end
1826
var
.
error
=
"
unknown component
"
1827
if
trace_identifying
then
1828
report_identify_outer
(
set
,
var
,
i
,
"
6c
"
)
1829
end
1830
return
var
1831
end
1832 1833
local
nofidentified
=
0
1834 1835
local
function
identify
(
prefix
,
reference
)
1836
if
not
reference
then
1837
prefix
,
reference
=
"
"
,
prefix
1838
end
1839
local
set
=
resolve
(
prefix
,
reference
)
1840
local
bug
=
false
1841
texsetcount
(
"
referencehastexstate
"
,
set
.
has_tex
and
1
or
0
)
1842
nofidentified
=
nofidentified
+
1
1843
set
.
n
=
nofidentified
1844
for
i
=
1
,
#
set
do
1845
local
var
=
set
[
i
]
1846
local
spe
=
var
.
special
1847
local
fnc
=
functions
[
spe
]
1848
if
fnc
then
1849
var
=
fnc
(
var
)
or
{
error
=
"
invalid special function
"
}
1850
elseif
spe
then
1851
var
=
identify_special
(
set
,
var
,
i
)
1852
elseif
var
.
outer
then
1853
var
=
identify_outer
(
set
,
var
,
i
)
1854
elseif
var
.
arguments
then
1855
var
=
identify_arguments
(
set
,
var
,
i
)
1856
elseif
not
var
.
component
then
1857
var
=
identify_inner_or_outer
(
set
,
var
,
i
)
1858
elseif
productcomponent
(
)
then
1859
var
=
identify_inner_component
(
set
,
var
,
i
)
1860
else
1861
var
=
identify_outer_component
(
set
,
var
,
i
)
1862
end
1863
set
[
i
]
=
var
1864
bug
=
bug
or
var
.
error
1865
end
1866
references
.
currentset
=
mark
(
set
)
-- mark, else in api doc
1867
if
trace_analyzing
then
1868
report_references
(
table
.
serialize
(
set
,
reference
)
)
1869
end
1870
return
set
,
bug
1871
end
1872 1873
references
.
identify
=
identify
1874 1875
local
unknowns
,
nofunknowns
,
f_valid
=
{
}
,
0
,
formatters
[
"
[%s][%s]
"
]
1876 1877
function
references
.
valid
(
prefix
,
reference
,
specification
)
1878
local
set
,
bug
=
identify
(
prefix
,
reference
)
1879
local
unknown
=
bug
or
#
set
=
=
0
1880
if
unknown
then
1881
currentreference
=
nil
-- will go away
1882
local
str
=
f_valid
(
prefix
,
reference
)
1883
local
u
=
unknowns
[
str
]
1884
if
not
u
then
1885
if
somefound
then
1886
interfaces
.
showmessage
(
"
references
"
,
1
,
str
)
-- 1 = unknown, 4 = illegal
1887
end
1888
unknowns
[
str
]
=
1
1889
nofunknowns
=
nofunknowns
+
1
1890
else
1891
unknowns
[
str
]
=
u
+
1
1892
end
1893
else
1894
set
.
highlight
=
specification
.
highlight
1895
set
.
newwindow
=
specification
.
newwindow
1896
set
.
layer
=
specification
.
layer
1897
currentreference
=
set
[
1
]
1898
end
1899
-- we can do the expansion here which saves a call
1900
return
not
unknown
1901
end
1902 1903
implement
{
1904
name
=
"
doifelsereference
"
,
1905
actions
=
{
references
.
valid
,
commands
.
doifelse
}
,
1906
arguments
=
{
1907
"
string
"
,
1908
"
string
"
,
1909
{
1910
{
"
highlight
"
,
"
boolean
"
}
,
1911
{
"
newwindow
"
,
"
boolean
"
}
,
1912
{
"
layer
"
}
,
1913
}
1914
}
1915
}
1916 1917
logs
.
registerfinalactions
(
function
(
)
1918
if
nofunknowns
>
0
then
1919
statistics
.
register
(
"
cross referencing
"
,
function
(
)
1920
return
format
(
"
%s identified, %s unknown
"
,
nofidentified
,
nofunknowns
)
1921
end
)
1922
local
sortedhash
=
table
.
sortedhash
1923
logs
.
startfilelogging
(
report
,
"
missing references
"
)
1924
for
k
,
v
in
table
.
sortedhash
(
unknowns
)
do
1925
report
(
"
%4i %s
"
,
v
,
k
)
1926
end
1927
logs
.
stopfilelogging
(
)
1928
if
logs
.
loggingerrors
(
)
then
1929
logs
.
starterrorlogging
(
report
,
"
missing references
"
)
1930
for
k
,
v
in
table
.
sortedhash
(
unknowns
)
do
1931
report
(
"
%4i %s
"
,
v
,
k
)
1932
end
1933
logs
.
stoperrorlogging
(
)
1934
end
1935
end
1936
end
)
1937 1938
-- The auto method will try to avoid named internals in a clever way which
1939
-- can make files smaller without sacrificing external references. Some of
1940
-- the housekeeping happens the backend side.
1941 1942
local
innermethod
=
v_auto
-- only page|auto now
1943
local
outermethod
=
v_auto
-- only page|auto now
1944
local
defaultinnermethod
=
defaultinnermethod
1945
local
defaultoutermethod
=
defaultoutermethod
1946
references
.
innermethod
=
innermethod
-- don't mess with this one directly
1947
references
.
outermethod
=
outermethod
-- don't mess with this one directly
1948 1949
function
references
.
setlinkmethod
(
inner
,
outer
)
1950
if
not
outer
and
type
(
inner
)
=
=
"
string
"
then
1951
local
m
=
settings_to_array
(
inner
)
1952
inner
=
m
[
1
]
1953
outer
=
m
[
2
]
or
v_auto
1954
end
1955
if
toboolean
(
inner
)
or
inner
=
=
v_page
or
inner
=
=
v_yes
then
1956
innermethod
=
v_page
1957
elseif
inner
=
=
v_name
then
1958
innermethod
=
v_name
1959
else
1960
innermethod
=
v_auto
1961
end
1962
if
toboolean
(
outer
)
or
outer
=
=
v_page
or
outer
=
=
v_yes
then
1963
outermethod
=
v_page
1964
elseif
inner
=
=
v_name
then
1965
outermethod
=
v_name
1966
else
1967
outermethod
=
v_auto
1968
end
1969
references
.
innermethod
=
innermethod
1970
references
.
outermethod
=
outermethod
1971
function
references
.
setlinkmethod
(
)
1972
report_references
(
"
link method is already set and frozen: inner %a, outer %a
"
,
innermethod
,
outermethod
)
1973
end
1974
end
1975 1976
implement
{
1977
name
=
"
setreferencelinkmethod
"
,
1978
actions
=
references
.
setlinkmethod
,
1979
arguments
=
"
string
"
,
1980
-- onlyonce = true
1981
}
1982 1983
function
references
.
getinnermethod
(
)
1984
return
innermethod
or
defaultinnermethod
1985
end
1986 1987
function
references
.
getoutermethod
(
)
1988
return
outermethod
or
defaultoutermethod
1989
end
1990 1991
directives
.
register
(
"
references.linkmethod
"
,
function
(
v
)
-- page auto
1992
references
.
setlinkmethod
(
v
)
1993
end
)
1994 1995
-- we can call setinternalreference with an already known internal or with
1996
-- a reference/prefix specification
1997 1998
local
destinationattributes
=
{
}
1999 2000
local
function
setinternalreference
(
specification
)
2001
local
internal
=
specification
.
internal
2002
local
destination
=
unsetvalue
2003
if
innermethod
=
=
v_auto
or
innermethod
=
=
v_name
then
2004
local
t
=
{
}
-- maybe add to current (now only used for tracing)
2005
local
tn
=
0
2006
local
reference
=
specification
.
reference
2007
local
view
=
specification
.
view
2008
if
reference
then
2009
local
prefix
=
specification
.
prefix
2010
if
prefix
and
prefix
~
=
"
"
then
2011
local
prefix
=
prefix
.
.
"
:
"
-- watch out, : here
2012
local
function
action
(
ref
)
2013
tn
=
tn
+
1
2014
t
[
tn
]
=
prefix
.
.
ref
2015
end
2016
process_settings
(
reference
,
action
)
2017
else
2018
local
function
action
(
ref
)
2019
tn
=
tn
+
1
2020
t
[
tn
]
=
ref
2021
end
2022
process_settings
(
reference
,
action
)
2023
end
2024
end
2025
-- ugly .. later we decide to ignore it when we have a real one
2026
-- but for testing we might want to see them all
2027
if
internal
then
2028
if
innermethod
~
=
v_name
then
-- innermethod == v_auto
2029
-- we don't want too many #1 #2 #3 etc
2030
tn
=
tn
+
1
2031
t
[
tn
]
=
internal
-- when number it's internal
2032
end
2033
if
not
view
then
2034
local
i
=
references
.
internals
[
internal
]
2035
if
i
then
2036
view
=
i
.
references
.
view
2037
end
2038
end
2039
end
2040
destination
=
references
.
mark
(
t
,
nil
,
nil
,
view
)
-- returns an attribute
2041
end
2042
if
internal
then
-- new
2043
destinationattributes
[
internal
]
=
destination
2044
end
2045
texsetcount
(
"
lastdestinationattribute
"
,
destination
)
2046
return
destination
2047
end
2048 2049
local
function
getinternalreference
(
internal
)
2050
return
destinationattributes
[
internal
]
or
0
2051
end
2052 2053
references
.
setinternalreference
=
setinternalreference
2054
references
.
getinternalreference
=
getinternalreference
2055 2056
implement
{
2057
name
=
"
setinternalreference
"
,
2058
actions
=
setinternalreference
,
2059
arguments
=
{
2060
{
2061
{
"
prefix
"
}
,
2062
{
"
reference
"
}
,
2063
{
"
internal
"
,
"
integer
"
}
,
2064
{
"
view
"
}
2065
}
2066
}
2067
}
2068 2069
-- implement {
2070
-- name = "getinternalreference",
2071
-- actions = { getinternalreference, context },
2072
-- arguments = "integer",
2073
-- }
2074 2075
function
references
.
setandgetattribute
(
data
)
-- maybe do internal automatically here
2076
local
attr
=
unsetvalue
2077
local
mdat
=
data
.
metadata
2078
local
rdat
=
data
.
references
2079
if
mdat
and
rdat
then
2080
if
not
rdat
.
section
then
2081
rdat
.
section
=
structures
.
sections
.
currentid
(
)
2082
end
2083
local
ndat
=
data
.
numberdata
2084
if
ndat
then
2085
local
numbers
=
ndat
.
numbers
2086
if
type
(
numbers
)
=
=
"
string
"
then
2087
ndat
.
numbers
=
counters
.
compact
(
numbers
,
nil
,
true
)
2088
end
2089
data
.
numberdata
=
helpers
.
simplify
(
ndat
)
2090
end
2091
local
pdat
=
data
.
prefixdata
2092
if
pdat
then
2093
data
.
prefixdata
=
helpers
.
simplify
(
pdat
)
2094
end
2095
local
udat
=
data
.
userdata
2096
if
type
(
udat
)
=
=
"
string
"
then
2097
data
.
userdata
=
helpers
.
touserdata
(
udat
)
2098
end
2099
if
not
rdat
.
block
then
2100
rdat
.
block
=
structures
.
sections
.
currentblock
(
)
2101
end
2102
local
done
=
references
.
set
(
data
)
-- we had kind i.e .item -> full
2103
if
done
then
2104
attr
=
setinternalreference
{
2105
prefix
=
rdat
.
prefix
,
2106
reference
=
rdat
.
reference
,
2107
internal
=
rdat
.
internal
,
2108
view
=
rdat
.
view
2109
}
or
unsetvalue
2110
end
2111
end
2112
texsetcount
(
"
lastdestinationattribute
"
,
attr
)
2113
return
attr
2114
end
2115 2116
implement
{
2117
name
=
"
setdestinationattribute
"
,
2118
actions
=
references
.
setandgetattribute
,
2119
arguments
=
{
2120
{
2121
{
2122
"
references
"
,
{
2123
{
"
internal
"
,
"
integer
"
}
,
2124
{
"
block
"
}
,
2125
{
"
view
"
}
,
2126
{
"
prefix
"
}
,
2127
{
"
reference
"
}
,
2128
}
,
2129
}
,
2130
{
2131
"
metadata
"
,
{
2132
{
"
kind
"
}
,
2133
{
"
xmlroot
"
}
,
2134
{
"
catcodes
"
,
"
integer
"
}
,
2135
}
,
2136
}
,
2137
{
2138
"
prefixdata
"
,
{
"
*
"
}
2139
}
,
2140
{
2141
"
numberdata
"
,
{
"
*
"
}
2142
}
,
2143
{
2144
"
entries
"
,
{
"
*
"
}
2145
}
,
2146
{
2147
"
userdata
"
2148
}
2149
}
2150
}
2151
}
2152 2153
function
references
.
getinternallistreference
(
n
)
-- n points into list (todo: registers)
2154
local
l
=
lists
.
collected
[
n
]
2155
local
i
=
l
and
l
.
references
.
internal
2156
return
i
and
destinationattributes
[
i
]
or
0
2157
end
2158 2159
function
references
.
getinternalcachedlistreference
(
n
)
-- n points into list (todo: registers)
2160
local
l
=
lists
.
cached
[
n
]
2161
local
i
=
l
and
l
.
references
.
internal
2162
return
i
and
destinationattributes
[
i
]
or
0
2163
end
2164 2165
implement
{
2166
name
=
"
getinternallistreference
"
,
2167
actions
=
{
references
.
getinternallistreference
,
context
}
,
2168
arguments
=
"
integer
"
2169
}
2170 2171
implement
{
2172
name
=
"
getinternalcachedlistreference
"
,
2173
actions
=
{
references
.
getinternalcachedlistreference
,
context
}
,
2174
arguments
=
"
integer
"
2175
}
2176 2177 2178
--
2179 2180
function
references
.
getcurrentmetadata
(
tag
)
2181
local
data
=
currentreference
and
currentreference
.
i
2182
return
data
and
data
.
metadata
and
data
.
metadata
[
tag
]
2183
end
2184 2185
implement
{
2186
name
=
"
getcurrentreferencemetadata
"
,
2187
actions
=
{
references
.
getcurrentmetadata
,
context
}
,
2188
arguments
=
"
string
"
,
2189
}
2190 2191
local
function
currentmetadata
(
tag
)
2192
local
data
=
currentreference
and
currentreference
.
i
2193
return
data
and
data
.
metadata
and
data
.
metadata
[
tag
]
2194
end
2195 2196
references
.
currentmetadata
=
currentmetadata
2197 2198
local
function
getcurrentprefixspec
(
default
)
2199
local
data
=
currentreference
and
currentreference
.
i
2200
local
metadata
=
data
and
data
.
metadata
2201
return
2202
metadata
and
metadata
.
kind
or
"
?
"
,
2203
metadata
and
metadata
.
name
or
"
?
"
,
2204
default
or
"
?
"
2205
end
2206 2207
references
.
getcurrentprefixspec
=
getcurrentprefixspec
2208 2209
-- implement {
2210
-- name = "getcurrentprefixspec",
2211
-- actions = { getcurrentprefixspec, context }, -- returns 3 arguments
2212
-- arguments = "string",
2213
-- }
2214 2215
implement
{
2216
name
=
"
getcurrentprefixspec
"
,
2217
actions
=
function
(
tag
)
2218
context
(
"
{%s}{%s}{%s}
"
,
getcurrentprefixspec
(
tag
)
)
2219
end
,
2220
arguments
=
"
string
"
,
2221
}
2222 2223
local
genericfilters
=
{
}
2224
local
userfilters
=
{
}
2225
local
textfilters
=
{
}
2226
local
fullfilters
=
{
}
2227
local
sectionfilters
=
{
}
2228 2229
filters
.
generic
=
genericfilters
2230
filters
.
user
=
userfilters
2231
filters
.
text
=
textfilters
2232
filters
.
full
=
fullfilters
2233
filters
.
section
=
sectionfilters
2234 2235
local
function
filterreference
(
name
,
prefixspec
,
numberspec
)
-- number page title ...
2236
local
data
=
currentreference
and
currentreference
.
i
-- maybe we should take realpage from here
2237
if
data
then
2238
if
name
=
=
"
realpage
"
then
2239
local
cs
=
references
.
analyze
(
)
-- normally already analyzed but also sets state
2240
context
(
tonumber
(
cs
.
realpage
)
or
0
)
2241
else
-- assumes data is table
2242
local
kind
=
type
(
data
)
=
=
"
table
"
and
data
.
metadata
and
data
.
metadata
.
kind
2243
if
kind
then
2244
local
filter
=
filters
[
kind
]
or
genericfilters
2245
filter
=
filter
and
(
filter
[
name
]
or
filter
.
unknown
or
genericfilters
[
name
]
or
genericfilters
.
unknown
)
2246
if
filter
then
2247
if
trace_referencing
then
2248
report_references
(
"
name %a, kind %a, using dedicated filter
"
,
name
,
kind
)
2249
end
2250
filter
(
data
,
name
,
prefixspec
,
numberspec
)
2251
elseif
trace_referencing
then
2252
report_references
(
"
name %a, kind %a, using generic filter
"
,
name
,
kind
)
2253
end
2254
elseif
trace_referencing
then
2255
report_references
(
"
name %a, unknown kind
"
,
name
)
2256
end
2257
end
2258
elseif
name
=
=
"
realpage
"
then
2259
context
(
0
)
2260
elseif
trace_referencing
then
2261
report_references
(
"
name %a, no reference
"
,
name
)
2262
end
2263
end
2264 2265
local
function
filterreferencedefault
(
)
2266
return
filterreference
(
"
default
"
,
getcurrentprefixspec
(
"
default
"
)
)
2267
end
2268 2269
references
.
filter
=
filterreference
2270
references
.
filterdefault
=
filterreferencedefault
2271 2272
implement
{
2273
name
=
"
filterreference
"
,
2274
actions
=
filterreference
,
2275
arguments
=
"
string
"
,
2276
}
2277 2278
implement
{
2279
name
=
"
filterdefaultreference
"
,
2280
actions
=
filterreference
,
2281
arguments
=
{
2282
"
string
"
,
-- 'default'
2283
{
{
"
*
"
}
}
,
-- prefixspec
2284
{
{
"
*
"
}
}
,
-- numberspec
2285
}
2286
}
2287 2288
function
genericfilters
.
title
(
data
)
2289
if
data
then
2290
local
titledata
=
data
.
titledata
or
data
.
useddata
2291
if
titledata
then
2292
helpers
.
title
(
titledata
.
title
or
"
?
"
,
data
.
metadata
)
2293
end
2294
end
2295
end
2296 2297
function
genericfilters
.
text
(
data
)
2298
if
data
then
2299
local
entries
=
data
.
entries
or
data
.
useddata
2300
if
entries
then
2301
helpers
.
title
(
entries
.
text
or
"
?
"
,
data
.
metadata
)
2302
end
2303
end
2304
end
2305 2306
function
genericfilters
.
number
(
data
,
what
,
prefixspec
,
numberspec
)
2307
if
data
then
2308
numberdata
=
lists
.
reordered
(
data
)
-- data.numberdata
2309
if
numberdata
then
2310
helpers
.
prefix
(
data
,
prefixspec
)
2311
sections
.
typesetnumber
(
numberdata
,
"
number
"
,
numberspec
,
numberdata
)
2312
else
2313
local
useddata
=
data
.
useddata
2314
if
useddata
and
useddata
.
number
then
2315
context
(
useddata
.
number
)
2316
end
2317
end
2318
end
2319
end
2320 2321
genericfilters
.
default
=
genericfilters
.
text
2322 2323
function
genericfilters
.
page
(
data
,
prefixspec
,
pagespec
)
2324
local
pagedata
=
data
.
pagedata
2325
if
pagedata
then
2326
local
number
=
pagedata
.
number
2327
local
conversion
=
pagedata
.
conversion
2328
if
not
number
then
2329
-- error
2330
elseif
conversion
then
2331
ctx_convertnumber
(
conversion
,
number
)
2332
else
2333
context
(
number
)
2334
end
2335
else
2336
helpers
.
prefixpage
(
data
,
prefixspec
,
pagespec
)
2337
end
2338
end
2339 2340
function
userfilters
.
unknown
(
data
,
name
)
2341
if
data
then
2342
local
userdata
=
data
.
userdata
2343
local
userkind
=
userdata
and
userdata
.
kind
2344
if
userkind
then
2345
local
filter
=
filters
[
userkind
]
or
genericfilters
2346
filter
=
filter
and
(
filter
[
name
]
or
filter
.
unknown
)
2347
if
filter
then
2348
filter
(
data
,
name
)
2349
return
2350
end
2351
end
2352
local
namedata
=
userdata
and
userdata
[
name
]
2353
if
namedata
then
2354
context
(
namedata
)
2355
end
2356
end
2357
end
2358 2359
function
textfilters
.
title
(
data
)
2360
helpers
.
title
(
data
.
entries
.
text
or
"
?
"
,
data
.
metadata
)
2361
end
2362 2363
-- no longer considered useful:
2364
--
2365
-- function filters.text.number(data)
2366
-- helpers.title(data.entries.text or "?",data.metadata)
2367
-- end
2368 2369
function
textfilters
.
page
(
data
,
prefixspec
,
pagespec
)
2370
helpers
.
prefixpage
(
data
,
prefixspec
,
pagespec
)
2371
end
2372 2373
fullfilters
.
title
=
textfilters
.
title
2374
fullfilters
.
page
=
textfilters
.
page
2375 2376
function
sectionfilters
.
number
(
data
,
what
,
prefixspec
)
2377
if
data
then
2378
local
numberdata
=
data
.
numberdata
2379
if
not
numberdata
then
2380
local
useddata
=
data
.
useddata
2381
if
useddata
and
useddata
.
number
then
2382
context
(
useddata
.
number
)
2383
end
2384
elseif
numberdata
.
hidenumber
then
2385
local
references
=
data
.
references
2386
if
trace_empty
then
2387
report_empty
(
"
reference %a has a hidden number
"
,
references
.
reference
)
2388
ctx_emptyreference
(
)
-- maybe an option
2389
end
2390
else
2391
sections
.
typesetnumber
(
numberdata
,
"
number
"
,
prefixspec
,
numberdata
)
2392
end
2393
end
2394
end
2395 2396
sectionfilters
.
title
=
genericfilters
.
title
2397
sectionfilters
.
page
=
genericfilters
.
page
2398
sectionfilters
.
default
=
sectionfilters
.
number
2399 2400
-- filters.note = { default = genericfilters.number }
2401
-- filters.formula = { default = genericfilters.number }
2402
-- filters.float = { default = genericfilters.number }
2403
-- filters.description = { default = genericfilters.number }
2404
-- filters.item = { default = genericfilters.number }
2405 2406
setmetatableindex
(
filters
,
function
(
t
,
k
)
-- beware, test with rawget
2407
local
v
=
{
default
=
genericfilters
.
number
}
-- not copy as it might be extended differently
2408
t
[
k
]
=
v
2409
return
v
2410
end
)
2411 2412
-- function references.sectiontitle(n)
2413
-- helpers.sectiontitle(lists.collected[tonumber(n) or 0])
2414
-- end
2415 2416
-- function references.sectionnumber(n)
2417
-- helpers.sectionnumber(lists.collected[tonumber(n) or 0])
2418
-- end
2419 2420
-- function references.sectionpage(n,prefixspec,pagespec)
2421
-- helpers.prefixedpage(lists.collected[tonumber(n) or 0],prefixspec,pagespec)
2422
-- end
2423 2424
-- analyze
2425 2426
references
.
testrunners
=
references
.
testrunners
or
{
}
2427
references
.
testspecials
=
references
.
testspecials
or
{
}
2428 2429
local
runners
=
references
.
testrunners
2430
local
specials
=
references
.
testspecials
2431 2432
-- We need to prevent ending up in the 'relative location' analyzer as it is
2433
-- pretty slow (progressively). In the pagebody one can best check the reference
2434
-- real page to determine if we need contrastlocation as that is more lightweight.
2435 2436
local
function
checkedpagestate
(
n
,
page
,
actions
,
position
,
spread
)
2437
local
p
=
tonumber
(
page
)
2438
if
not
p
then
2439
return
0
2440
end
2441
if
position
and
#
actions
>
0
then
2442
local
i
=
actions
[
1
]
.
i
-- brrr
2443
if
i
then
2444
local
a
=
i
.
references
2445
if
a
then
2446
local
x
=
a
.
x
2447
local
y
=
a
.
y
2448
if
x
and
y
then
2449
local
jp
=
jobpositions
.
collected
[
position
]
2450
if
jp
then
2451
local
px
=
jp
.
x
2452
local
py
=
jp
.
y
2453
local
pp
=
jp
.
p
2454
if
p
=
=
pp
then
2455
-- same page
2456
if
py
>
y
then
2457
return
5
-- above
2458
elseif
py
<
y
then
2459
return
4
-- below
2460
elseif
px
>
x
then
2461
return
4
-- below
2462
elseif
px
<
x
then
2463
return
5
-- above
2464
else
2465
return
1
-- same
2466
end
2467
elseif
spread
then
2468
if
pp
%
2
=
=
0
then
2469
-- left page
2470
if
pp
>
p
then
2471
return
2
-- before
2472
elseif
pp
+
1
=
=
p
then
2473
-- return 4 -- below (on right page)
2474
return
5
-- above (on left page)
2475
else
2476
return
3
-- after
2477
end
2478
else
2479
-- right page
2480
if
pp
<
p
then
2481
return
3
-- after
2482
elseif
pp
-
1
=
=
p
then
2483
-- return 5 -- above (on left page)
2484
return
4
-- below (on right page)
2485
else
2486
return
2
-- before
2487
end
2488
end
2489
elseif
pp
>
p
then
2490
return
2
-- before
2491
else
2492
return
3
-- after
2493
end
2494
end
2495
end
2496
end
2497
end
2498
end
2499
local
r
=
referredpage
(
n
)
-- sort of obsolete
2500
if
p
>
r
then
2501
return
3
-- after
2502
elseif
p
<
r
then
2503
return
2
-- before
2504
else
2505
return
1
-- same
2506
end
2507
end
2508 2509
local
function
setreferencerealpage
(
actions
)
2510
if
not
actions
then
2511
actions
=
references
.
currentset
2512
end
2513
if
type
(
actions
)
=
=
"
table
"
then
2514
local
realpage
=
actions
.
realpage
2515
if
realpage
then
2516
return
realpage
2517
end
2518
local
nofactions
=
#
actions
2519
if
nofactions
>
0
then
2520
for
i
=
1
,
nofactions
do
2521
local
a
=
actions
[
i
]
2522
local
what
=
runners
[
a
.
kind
]
2523
if
what
then
2524
what
=
what
(
a
,
actions
)
-- needs documentation
2525
end
2526
end
2527
realpage
=
actions
.
realpage
2528
if
realpage
then
2529
return
realpage
2530
end
2531
end
2532
actions
.
realpage
=
0
2533
end
2534
return
0
2535
end
2536 2537
references
.
setreferencerealpage
=
setreferencerealpage
2538 2539
-- we store some analysis data alongside the indexed array
2540
-- at this moment only the real reference page is analyzed
2541
-- normally such an analysis happens in the backend code
2542 2543
function
references
.
analyze
(
actions
,
position
,
spread
)
2544
if
not
actions
then
2545
actions
=
references
.
currentset
2546
end
2547
if
not
actions
then
2548
actions
=
{
realpage
=
0
,
pagestate
=
0
}
2549
elseif
actions
.
pagestate
then
2550
-- already done
2551
else
2552
local
realpage
=
actions
.
realpage
or
setreferencerealpage
(
actions
)
2553
if
realpage
=
=
0
then
2554
actions
.
pagestate
=
0
2555
elseif
actions
.
external
then
2556
actions
.
pagestate
=
0
2557
else
2558
actions
.
pagestate
=
checkedpagestate
(
actions
.
n
,
realpage
,
actions
,
position
,
spread
)
2559
end
2560
end
2561
return
actions
2562
end
2563 2564
local
function
referencepagestate
(
position
,
detail
,
spread
)
2565
local
actions
=
references
.
currentset
2566
if
not
actions
then
2567
return
0
2568
else
2569
local
pagestate
=
actions
.
pagestate
2570
for
i
=
1
,
#
actions
do
2571
local
a
=
actions
[
i
]
2572
if
a
.
outer
then
2573
pagestate
=
0
2574
actions
.
pagestate
=
pagestate
2575
break
2576
end
2577
end
2578
if
not
pagestate
then
2579
references
.
analyze
(
actions
,
position
,
spread
)
-- delayed unless explicitly asked for
2580
pagestate
=
actions
.
pagestate
2581
end
2582
if
detail
then
2583
return
pagestate
2584
elseif
pagestate
=
=
4
then
2585
return
2
-- compatible
2586
elseif
pagestate
=
=
5
then
2587
return
3
-- compatible
2588
else
2589
return
pagestate
2590
end
2591
end
2592
end
2593 2594
implement
{
2595
name
=
"
referencepagestate
"
,
2596
actions
=
{
referencepagestate
,
context
}
,
2597
arguments
=
"
string
"
2598
}
2599 2600
implement
{
2601
name
=
"
referencepagedetail
"
,
2602
actions
=
{
referencepagestate
,
context
}
,
2603
arguments
=
{
"
string
"
,
"
boolean
"
,
"
boolean
"
}
2604
}
2605 2606
-- local function referencerealpage()
2607
-- local actions = references.currentset
2608
-- return not actions and 0 or actions.realpage or setreferencerealpage(actions)
2609
-- end
2610
--
2611
-- implement {
2612
-- name = "referencerealpage",
2613
-- actions = { referencerealpage, context },
2614
-- -- arguments = "string" -- hm, weird
2615
-- }
2616 2617
implement
{
2618
name
=
"
askedreference
"
,
2619
public
=
true
,
2620
actions
=
function
(
)
2621
local
actions
=
references
.
currentset
2622
if
actions
then
2623
context
(
"
[p=%s,r=%s]
"
,
actions
.
prefix
or
"
"
,
actions
.
reference
)
2624
end
2625
end
2626
}
2627 2628
implement
{
2629
name
=
"
referencerealpage
"
,
2630
actions
=
function
(
)
2631
local
actions
=
references
.
currentset
2632
context
(
not
actions
and
0
or
actions
.
realpage
or
setreferencerealpage
(
actions
)
)
2633
end
2634
}
2635 2636
local
function
referencepos
(
key
)
2637
local
actions
=
references
.
currentset
2638
local
i
=
actions
[
1
]
.
i
-- brrr
2639
local
v
=
0
2640
if
i
then
2641
local
a
=
i
.
references
2642
if
a
then
2643
v
=
a
[
key
]
or
0
2644
end
2645
end
2646
return
v
2647
end
2648 2649
implement
{
name
=
"
referenceposx
"
,
actions
=
function
(
)
context
(
"
%p
"
,
referencepos
(
"
x
"
)
)
end
}
2650
implement
{
name
=
"
referenceposy
"
,
actions
=
function
(
)
context
(
"
%p
"
,
referencepos
(
"
y
"
)
)
end
}
2651 2652 2653
implement
{
2654
name
=
"
referencecolumn
"
,
2655
actions
=
function
(
)
2656
local
actions
=
references
.
currentset
2657
local
column
=
1
2658
if
actions
then
2659
column
=
jobpositions
.
columnofpos
(
actions
.
realpage
or
setreferencerealpage
(
actions
)
,
referencepos
(
"
x
"
)
)
2660
end
2661
context
(
column
or
1
)
2662
end
2663
}
2664 2665
local
plist
,
nofrealpages
2666 2667
local
function
realpageofpage
(
p
)
-- the last one counts !
2668
if
not
plist
then
2669
local
pages
=
structures
.
pages
.
collected
2670
nofrealpages
=
#
pages
2671
plist
=
{
}
2672
for
rp
=
1
,
nofrealpages
do
2673
local
page
=
pages
[
rp
]
2674
if
page
then
2675
plist
[
page
.
number
]
=
rp
2676
end
2677
end
2678
references
.
nofrealpages
=
nofrealpages
2679
end
2680
return
plist
[
p
]
2681
end
2682 2683
references
.
realpageofpage
=
realpageofpage
2684 2685
function
references
.
checkedrealpage
(
r
)
2686
if
not
plist
then
2687
realpageofpage
(
r
)
-- just initialize
2688
end
2689
if
not
r
then
2690
return
texgetcount
(
"
realpageno
"
)
2691
elseif
r
<
1
then
2692
return
1
2693
elseif
r
>
nofrealpages
then
2694
return
nofrealpages
2695
else
2696
return
r
2697
end
2698
end
2699 2700
-- use local ?
2701 2702
local
pages
=
allocate
{
2703
[
variables
.
firstpage
]
=
function
(
)
return
counters
.
record
(
"
realpage
"
)
[
"
first
"
]
end
,
2704
[
variables
.
previouspage
]
=
function
(
)
return
counters
.
record
(
"
realpage
"
)
[
"
previous
"
]
end
,
2705
[
variables
.
nextpage
]
=
function
(
)
return
counters
.
record
(
"
realpage
"
)
[
"
next
"
]
end
,
2706
[
variables
.
lastpage
]
=
function
(
)
return
counters
.
record
(
"
realpage
"
)
[
"
last
"
]
end
,
2707 2708
[
variables
.
firstsubpage
]
=
function
(
)
return
counters
.
record
(
"
subpage
"
)
[
"
first
"
]
end
,
2709
[
variables
.
previoussubpage
]
=
function
(
)
return
counters
.
record
(
"
subpage
"
)
[
"
previous
"
]
end
,
2710
[
variables
.
nextsubpage
]
=
function
(
)
return
counters
.
record
(
"
subpage
"
)
[
"
next
"
]
end
,
2711
[
variables
.
lastsubpage
]
=
function
(
)
return
counters
.
record
(
"
subpage
"
)
[
"
last
"
]
end
,
2712 2713
[
variables
.
forward
]
=
function
(
)
return
counters
.
record
(
"
realpage
"
)
[
"
forward
"
]
end
,
2714
[
variables
.
backward
]
=
function
(
)
return
counters
.
record
(
"
realpage
"
)
[
"
backward
"
]
end
,
2715
}
2716 2717
references
.
pages
=
pages
2718 2719
-- maybe some day i will merge this in the backend code with a testmode (so each
2720
-- runner then implements a branch)
2721 2722
runners
[
"
inner
"
]
=
function
(
var
,
actions
)
2723
local
r
=
var
.
r
2724
if
r
then
2725
actions
.
realpage
=
r
2726
end
2727
end
2728 2729
runners
[
"
special
"
]
=
function
(
var
,
actions
)
2730
local
handler
=
specials
[
var
.
special
]
2731
return
handler
and
handler
(
var
,
actions
)
2732
end
2733 2734
runners
[
"
special operation
"
]
=
runners
[
"
special
"
]
2735
runners
[
"
special operation with arguments
"
]
=
runners
[
"
special
"
]
2736 2737
function
specials
.
internal
(
var
,
actions
)
2738
local
v
=
internals
[
tonumber
(
var
.
operation
)
]
2739
local
r
=
v
and
v
.
references
2740
if
r
then
2741
local
p
=
r
.
realpage
2742
if
p
then
2743
-- setmetatableindex(actions,r)
2744
actions
.
realpage
=
p
2745
actions
.
view
=
r
.
view
2746
end
2747
end
2748
end
2749 2750
specials
.
i
=
specials
.
internal
2751 2752
function
specials
.
page
(
var
,
actions
)
2753
local
o
=
var
.
operation
2754
local
p
=
pages
[
o
]
2755
if
type
(
p
)
=
=
"
function
"
then
2756
p
=
p
(
)
2757
else
2758
p
=
tonumber
(
realpageofpage
(
tonumber
(
o
)
)
)
2759
end
2760
if
p
then
2761
var
.
r
=
p
2762
actions
.
realpage
=
actions
.
realpage
or
p
-- first wins
2763
end
2764
end
2765 2766
function
specials
.
realpage
(
var
,
actions
)
2767
local
p
=
tonumber
(
var
.
operation
)
2768
if
p
then
2769
var
.
r
=
p
2770
actions
.
realpage
=
actions
.
realpage
or
p
-- first wins
2771
end
2772
end
2773 2774
function
specials
.
userpage
(
var
,
actions
)
2775
local
p
=
tonumber
(
realpageofpage
(
var
.
operation
)
)
2776
if
p
then
2777
var
.
r
=
p
2778
actions
.
realpage
=
actions
.
realpage
or
p
-- first wins
2779
end
2780
end
2781 2782
function
specials
.
deltapage
(
var
,
actions
)
2783
local
p
=
tonumber
(
var
.
operation
)
2784
if
p
then
2785
p
=
references
.
checkedrealpage
(
p
+
texgetcount
(
"
realpageno
"
)
)
2786
var
.
r
=
p
2787
actions
.
realpage
=
actions
.
realpage
or
p
-- first wins
2788
end
2789
end
2790 2791
function
specials
.
section
(
var
,
actions
)
2792
local
sectionname
=
var
.
arguments
2793
local
destination
=
var
.
operation
2794
local
internal
=
structures
.
sections
.
internalreference
(
sectionname
,
destination
)
2795
if
internal
then
2796
var
.
special
=
"
internal
"
2797
var
.
operation
=
internal
2798
var
.
arguments
=
nil
2799
specials
.
internal
(
var
,
actions
)
2800
end
2801
end
2802 2803
-- experimental:
2804 2805
local
p_splitter
=
lpeg
.
splitat
(
"
:
"
)
2806
local
p_lower
=
lpeg
.
patterns
.
utf8lower
2807 2808
-- We can cache lowercased titles which saves a lot of time, but then
2809
-- we can better have a global cache with weak keys.
2810 2811
-- local lowercache = table.setmetatableindex(function(t,k)
2812
-- local v = lpegmatch(p_lower,k)
2813
-- t[k] = v
2814
-- return v
2815
-- end)
2816 2817
local
lowercache
=
false
2818 2819
local
function
locate
(
list
,
askedkind
,
askedname
,
pattern
)
2820
local
kinds
=
lists
.
kinds
2821
local
names
=
lists
.
names
2822
if
askedkind
and
not
kinds
[
askedkind
]
then
2823
return
false
2824
end
2825
if
askedname
and
not
names
[
askedname
]
then
2826
return
false
2827
end
2828
for
i
=
1
,
#
list
do
2829
local
entry
=
list
[
i
]
2830
local
metadata
=
entry
.
metadata
2831
if
metadata
then
2832
local
found
=
false
2833
if
askedname
then
2834
local
name
=
metadata
.
name
2835
if
name
then
2836
found
=
name
=
=
askedname
2837
end
2838
elseif
askedkind
then
2839
local
kind
=
metadata
.
kind
2840
if
kind
then
2841
found
=
kind
=
=
askedkind
2842
end
2843
end
2844
if
found
then
2845
local
titledata
=
entry
.
titledata
2846
if
titledata
then
2847
local
title
=
titledata
.
title
2848
if
title
then
2849
if
lowercache
then
2850
found
=
lpegmatch
(
pattern
,
lowercache
[
title
]
)
2851
else
2852
found
=
lpegmatch
(
pattern
,
lpegmatch
(
p_lower
,
title
)
)
2853
end
2854
if
found
then
2855
return
{
2856
inner
=
pattern
,
2857
kind
=
"
inner
"
,
2858
reference
=
pattern
,
2859
i
=
entry
,
2860
p
=
"
"
,
2861
r
=
entry
.
references
.
realpage
,
2862
}
2863
end
2864
end
2865
end
2866
end
2867
end
2868
end
2869
end
2870 2871
function
functions
.
match
(
var
,
actions
)
2872
if
not
var
.
outer
then
2873
local
operation
=
var
.
operation
2874
if
operation
and
operation
~
=
"
"
then
2875
local
operation
=
lpegmatch
(
p_lower
,
operation
)
2876
local
list
=
lists
.
collected
2877
local
names
=
false
2878
local
kinds
=
false
2879
local
where
,
what
=
lpegmatch
(
p_splitter
,
operation
)
2880
if
where
and
what
then
2881
local
pattern
=
lpeg
.
finder
(
what
)
2882
return
2883
locate
(
list
,
false
,
where
,
pattern
)
2884
or
locate
(
list
,
where
,
false
,
pattern
)
2885
or
{
error
=
"
no match
"
}
2886
else
2887
local
pattern
=
lpeg
.
finder
(
operation
)
2888
-- todo: don't look at section and float in last pass
2889
return
2890
locate
(
list
,
"
section
"
,
false
,
pattern
)
2891
or
locate
(
list
,
"
float
"
,
false
,
pattern
)
2892
or
locate
(
list
,
false
,
false
,
pattern
)
2893
or
{
error
=
"
no match
"
}
2894
end
2895
end
2896
end
2897
end
2898 2899
-- needs a better split ^^^
2900 2901
-- done differently now:
2902 2903
function
references
.
export
(
usedname
)
end
2904
function
references
.
import
(
usedname
)
end
2905
function
references
.
load
(
usedname
)
end
2906 2907
implement
{
name
=
"
exportreferences
"
,
actions
=
references
.
export
}
2908 2909
-- better done here .... we don't insert/remove, just use a pointer
2910 2911
local
prefixstack
=
{
"
"
}
2912
local
prefixlevel
=
1
2913 2914
local
function
pushreferenceprefix
(
prefix
)
2915
prefixlevel
=
prefixlevel
+
1
2916
prefixstack
[
prefixlevel
]
=
prefix
2917
return
prefix
2918
end
2919 2920
local
function
popreferenceprefix
(
)
2921
prefixlevel
=
prefixlevel
-
1
2922
if
prefixlevel
>
0
then
2923
return
prefixstack
[
prefixlevel
]
2924
else
2925
report_references
(
"
unable to pop referenceprefix
"
)
2926
return
"
"
2927
end
2928
end
2929 2930
implement
{
2931
name
=
"
pushreferenceprefix
"
,
2932
actions
=
{
pushreferenceprefix
,
context
}
,
-- we can use setmacro
2933
arguments
=
"
string
"
,
2934
}
2935 2936
implement
{
2937
name
=
"
popreferenceprefix
"
,
2938
actions
=
{
popreferenceprefix
,
context
}
,
-- we can use setmacro
2939
}
2940