1if not modules then modules = { } end modules ['strc-pag'] = {
2 version = 1.001,
3 comment = "companion to strc-pag.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
9local allocate, mark = utilities.storage.allocate, utilities.storage.mark
10
11local trace_pages = false trackers.register("structures.pages", function(v) trace_pages = v end)
12
13local report_pages = logs.reporter("structure","pages")
14
15local structures = structures
16
17local helpers = structures.helpers
18local sections = structures.sections
19local pages = structures.pages
20local sets = structures.sets
21local counters = structures.counters
22
23local counterdata = counters.data
24
25local variables = interfaces.variables
26local context = context
27local commands = commands
28local implement = interfaces.implement
29
30local processors = typesetters.processors
31local applyprocessor = processors.apply
32local startapplyprocessor = processors.startapply
33local stopapplyprocessor = processors.stopapply
34
35local texsetcount = tex.setcount
36local texgetcount = tex.getcount
37
38local texconditionals = tex.conditionals
39
40local ctx_convertnumber = context.convertnumber
41
42
43
44local collected, tobesaved = allocate(), allocate()
45
46pages.collected = collected
47pages.tobesaved = tobesaved
48pages.nofpages = 0
49
50
51
52local function initializer()
53 collected = pages.collected
54 tobesaved = pages.tobesaved
55
56
57
58 local n = 0
59 for k in next, collected do
60 if k > n then
61 n = k
62 end
63 end
64 pages.nofpages = n
65end
66
67job.register('structures.pages.collected', tobesaved, initializer)
68
69local specification = { }
70
71function pages.save(prefixdata,numberdata,extradata)
72 local realpage = texgetcount("realpageno")
73 local userpage = texgetcount("userpageno")
74 if realpage > 0 then
75 if trace_pages then
76 report_pages("saving page %s.%s",realpage,userpage)
77 end
78 local viewerprefix = extradata.viewerprefix
79 local state = extradata.state
80 local label = extradata.label
81 local data = {
82 number = userpage,
83 viewerprefix = viewerprefix ~= "" and viewerprefix or nil,
84 state = state ~= "" and state or nil,
85 block = sections.currentblock(),
86 prefixdata = prefixdata and helpers.simplify(prefixdata),
87 numberdata = numberdata and helpers.simplify(numberdata),
88 marked = pages.markedlist(realpage),
89 label = label and label ~= "" and label,
90 }
91 tobesaved[realpage] = data
92 if not collected[realpage] then
93 collected[realpage] = data
94 end
95 elseif trace_pages then
96 report_pages("not saving page %s.%s",realpage,userpage)
97 end
98end
99
100
101
102
103function counters.specials.userpage()
104 local r = texgetcount("realpageno")
105 if r > 0 then
106 local t = tobesaved[r]
107 if t then
108 t.number = texgetcount("userpageno")
109 if trace_pages then
110 report_pages("forcing pagenumber of realpage %s to %s",r,t.number)
111 end
112 return
113 end
114 end
115 local u = texgetcount("userpageno")
116 if u == 0 then
117 if trace_pages then
118 report_pages("forcing pagenumber of realpage %s to %s (probably a bug)",r,1)
119 end
120 counters.setvalue("userpage",1)
121 texsetcount("userpageno",1)
122 end
123end
124
125
126
127
128
129
130
131function pages.number(realdata,pagespec)
132 local userpage = realdata.number
133 local block = realdata.block or ""
134 local numberspec = realdata.numberdata
135 local conversionset = (pagespec and pagespec.conversionset ~= "" and pagespec.conversionset) or (numberspec and numberspec.conversionset ~= "" and numberspec.conversionset) or ""
136 local conversion = (pagespec and pagespec.conversion ~= "" and pagespec.conversion ) or (numberspec and numberspec.conversion ~= "" and numberspec.conversion ) or ""
137 local starter = (pagespec and pagespec.starter ~= "" and pagespec.starter ) or (numberspec and numberspec.starter ~= "" and numberspec.starter ) or ""
138 local stopper = (pagespec and pagespec.stopper ~= "" and pagespec.stopper ) or (numberspec and numberspec.stopper ~= "" and numberspec.stopper ) or ""
139 if starter ~= "" then
140 applyprocessor(starter)
141 end
142 if conversion ~= "" then
143 ctx_convertnumber(conversion,userpage)
144 else
145 if conversionset == "" then conversionset = "default" end
146 local theconversion = sets.get("structure:conversions",block,conversionset,1,"numbers")
147 local data = startapplyprocessor(theconversion)
148 ctx_convertnumber(data or "number",userpage)
149 stopapplyprocessor()
150 end
151 if stopper ~= "" then
152 applyprocessor(stopper)
153 end
154end
155
156
157
158function pages.analyze(entry,pagespecification)
159
160 if not entry then
161 return false, false, "no entry"
162 end
163 local references = entry.references
164 if not references then
165 return false, false, "no references"
166 end
167 local pagedata = references.pagedata
168 if not pagedata then
169 local realpage = references.realpage
170 if realpage then
171 pagedata = collected[realpage]
172 else
173 return false, false, "no realpage"
174 end
175 end
176 if not pagedata then
177 return false, false, "no pagedata"
178 end
179 local sectiondata = references.sectiondata
180 if not sectiondata then
181 local section = references.section
182 if section then
183 sectiondata = sections.collected[section]
184 else
185 return pagedata, false, "no section"
186 end
187 end
188 if not sectiondata then
189 return pagedata, false, "no sectiondata"
190 end
191 local v_no = variables.no
192
193 if pagespecification and pagespecification.prefix == v_no then
194 return pagedata, false, "current spec blocks prefix"
195 end
196
197
198
199
200
201 pagespecification = pagedata.prefixdata
202 if pagespecification and pagespecification.prefix == v_no then
203 return pagedata, false, "pagedata blocks prefix"
204 end
205
206 return pagedata, sectiondata, "okay"
207end
208
209function helpers.page(data,pagespec)
210 if data then
211 local pagedata = pages.analyze(data,pagespec)
212 if pagedata then
213 pages.number(pagedata,pagespec)
214 end
215 end
216end
217
218function helpers.prefixpage(data,prefixspec,pagespec)
219 if data then
220 local pagedata, prefixdata, e = pages.analyze(data,pagespec)
221 if pagedata then
222 if prefixdata then
223 sections.typesetnumber(prefixdata,"prefix",prefixspec or false,prefixdata or false,pagedata.prefixdata or false)
224 end
225 pages.number(pagedata,pagespec)
226 end
227 end
228end
229
230function helpers.prefixlastpage(data,prefixspec,pagespec)
231 if data then
232 local r = data.references
233 local ls = r.section
234 local lr = r.realpage
235 r.section = r.lastsection or r.section
236 r.realpage = r.lastrealpage or r.realpage
237 helpers.prefixpage(data,prefixspec,pagespec)
238 r.section, r.realpage = ls, lr
239 end
240end
241
242
243
244function helpers.analyze(entry,specification)
245
246 if not entry then
247 return false, false, "no entry"
248 end
249 local yes = variables.yes
250 local no = variables.no
251
252 local references = entry.references
253 if not references then
254 return entry, false, "no references"
255 end
256 local section = references.section
257 if not section then
258 return entry, false, "no section"
259 end
260 local sectiondata = references.sectiondata or sections.collected[references.section]
261 if not sectiondata then
262 return entry, false, "no section data"
263 end
264
265 if specification and specification.prefix == no then
266 return entry, false, "current spec blocks prefix"
267 end
268
269 local prefixdata = entry.prefixdata
270 if prefixdata and prefixdata.prefix == no then
271 return entry, false, "entry blocks prefix"
272 end
273
274 return entry, sectiondata, "okay"
275end
276
277function helpers.prefix(data,prefixspec,nosuffix)
278 if data then
279 local _, prefixdata, status = helpers.analyze(data,prefixspec)
280 if prefixdata then
281 if nosuffix and prefixspec then
282 local connector = prefixspec.connector
283 prefixspec.connector = nil
284 sections.typesetnumber(prefixdata,"prefix",prefixspec or false,data.prefixdata or false,prefixdata or false)
285 prefixspec.connector = connector
286 else
287 sections.typesetnumber(prefixdata,"prefix",prefixspec or false,data.prefixdata or false,prefixdata or false)
288 end
289 end
290 end
291end
292
293function helpers.pageofinternal(n,prefixspec,pagespec)
294 local data = structures.references.internals[n]
295 if not data then
296
297 elseif prefixspec then
298 helpers.prefixpage(data,prefixspec,pagespec)
299 else
300 helpers.prefix(data,pagespec)
301 end
302end
303
304function pages.is_odd(n)
305 n = n or texgetcount("realpageno")
306 if texgetcount("pagenoshift") % 2 == 0 then
307 return n % 2 ~= 0
308 else
309 return n % 2 == 0
310 end
311end
312
313function pages.on_right(n)
314 local pagemode = texgetcount("pageduplexmode")
315 if pagemode == 2 or pagemode == 1 then
316 n = n or texgetcount("realpageno")
317 if texgetcount("pagenoshift") % 2 == 0 then
318 return n % 2 ~= 0
319 else
320 return n % 2 == 0
321 end
322 else
323 return true
324 end
325end
326
327function pages.in_body(n)
328 return texgetcount("pagebodymode") > 0
329end
330
331function pages.fraction(n)
332 local lastpage = texgetcount("lastpageno")
333 return lastpage > 1 and (texgetcount("realpageno")-1)/(lastpage-1) or 1
334end
335
336
337
338function counters.analyze(name,counterspecification)
339 local cd = counterdata[name]
340
341 if not cd then
342 return false, false, "no counter data"
343 end
344
345 local sectiondata = sections.current()
346 if not sectiondata then
347 return cd, false, "not in section"
348 end
349 local references = sectiondata.references
350 if not references then
351 return cd, false, "no references"
352 end
353 local section = references.section
354 if not section then
355 return cd, false, "no section"
356 end
357 sectiondata = sections.collected[references.section]
358 if not sectiondata then
359 return cd, false, "no section data"
360 end
361
362 local no = variables.no
363 if counterspecification and counterspecification.prefix == no then
364 return cd, false, "current spec blocks prefix"
365 end
366
367 if cd.prefix == no then
368 return cd, false, "entry blocks prefix"
369 end
370
371
372
373
374
375 return cd, sectiondata, "okay"
376end
377
378function sections.prefixedconverted(name,prefixspec,numberspec)
379 local cd, prefixdata, result = counters.analyze(name,prefixspec)
380 if cd then
381 if prefixdata then
382 sections.typesetnumber(prefixdata,"prefix",prefixspec or false,cd or false)
383 end
384 counters.converted(name,numberspec)
385 end
386end
387
388function pages.getlabels()
389 local pages = structures.pages.tobesaved
390 local labels = false
391 for i=1,#pages do
392 local p = pages[i]
393 if p then
394 local label = p.label
395 if label and label ~= "" then
396 if not labels then
397 labels = { }
398 end
399 local l = labels[label]
400 local t = type(l)
401 if t == "number" then
402 l = { l, i }
403 elseif t == "table" then
404 l[#l+1] = i
405 else
406 l = i
407 end
408 labels[label] = l
409 end
410 end
411 end
412 return labels
413end
414
415
416
417implement {
418 name = "savepagedata",
419 actions = pages.save,
420 arguments = {
421 {
422 { "prefix" },
423 { "separatorset" },
424 { "conversionset" },
425 { "conversion" },
426 { "set" },
427 { "segments" },
428 { "connector" },
429 },
430 {
431 { "conversionset" },
432 { "conversion" },
433 { "starter" },
434 { "stopper" },
435 },
436 {
437 { "viewerprefix" },
438 { "state" },
439 { "label" },
440 }
441 }
442}
443
444implement {
445 name = "prefixedconverted",
446 actions = sections.prefixedconverted,
447 arguments = {
448 "string",
449 {
450 { "prefix" },
451 { "separatorset" },
452 { "conversionset" },
453 { "conversion" },
454 { "starter" },
455 { "stopper" },
456 { "set" },
457 { "segments" },
458 { "connector" },
459 },
460 {
461 { "order" },
462 { "separatorset" },
463 { "conversionset" },
464 { "conversion" },
465 { "starter" },
466 { "stopper" },
467 { "segments" },
468 { "type" },
469 { "criterium" },
470 }
471 }
472}
473
474interfaces.implement {
475 name = "pageofinternal",
476 arguments = "integer",
477 actions = helpers.pageofinternal,
478}
479 |