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 data = {
81 number = userpage,
82 viewerprefix = viewerprefix ~= "" and viewerprefix or nil,
83 state = state ~= "" and state or nil,
84 block = sections.currentblock(),
85 prefixdata = prefixdata and helpers.simplify(prefixdata),
86 numberdata = numberdata and helpers.simplify(numberdata),
87 marked = pages.markedlist(realpage),
88 }
89 tobesaved[realpage] = data
90 if not collected[realpage] then
91 collected[realpage] = data
92 end
93 elseif trace_pages then
94 report_pages("not saving page %s.%s",realpage,userpage)
95 end
96end
97
98
99
100
101function counters.specials.userpage()
102 local r = texgetcount("realpageno")
103 if r > 0 then
104 local t = tobesaved[r]
105 if t then
106 t.number = texgetcount("userpageno")
107 if trace_pages then
108 report_pages("forcing pagenumber of realpage %s to %s",r,t.number)
109 end
110 return
111 end
112 end
113 local u = texgetcount("userpageno")
114 if u == 0 then
115 if trace_pages then
116 report_pages("forcing pagenumber of realpage %s to %s (probably a bug)",r,1)
117 end
118 counters.setvalue("userpage",1)
119 texsetcount("userpageno",1)
120 end
121end
122
123
124
125
126
127
128
129function pages.number(realdata,pagespec)
130 local userpage = realdata.number
131 local block = realdata.block or ""
132 local numberspec = realdata.numberdata
133 local conversionset = (pagespec and pagespec.conversionset ~= "" and pagespec.conversionset) or (numberspec and numberspec.conversionset ~= "" and numberspec.conversionset) or ""
134 local conversion = (pagespec and pagespec.conversion ~= "" and pagespec.conversion ) or (numberspec and numberspec.conversion ~= "" and numberspec.conversion ) or ""
135 local starter = (pagespec and pagespec.starter ~= "" and pagespec.starter ) or (numberspec and numberspec.starter ~= "" and numberspec.starter ) or ""
136 local stopper = (pagespec and pagespec.stopper ~= "" and pagespec.stopper ) or (numberspec and numberspec.stopper ~= "" and numberspec.stopper ) or ""
137 if starter ~= "" then
138 applyprocessor(starter)
139 end
140 if conversion ~= "" then
141 ctx_convertnumber(conversion,userpage)
142 else
143 if conversionset == "" then conversionset = "default" end
144 local theconversion = sets.get("structure:conversions",block,conversionset,1,"numbers")
145 local data = startapplyprocessor(theconversion)
146 ctx_convertnumber(data or "number",userpage)
147 stopapplyprocessor()
148 end
149 if stopper ~= "" then
150 applyprocessors(stopper)
151 end
152end
153
154
155
156function pages.analyze(entry,pagespecification)
157
158 if not entry then
159 return false, false, "no entry"
160 end
161 local references = entry.references
162 if not references then
163 return false, false, "no references"
164 end
165 local pagedata = references.pagedata
166 if not pagedata then
167 local realpage = references.realpage
168 if realpage then
169 pagedata = collected[realpage]
170 else
171 return false, false, "no realpage"
172 end
173 end
174 if not pagedata then
175 return false, false, "no pagedata"
176 end
177 local sectiondata = references.sectiondata
178 if not sectiondata then
179 local section = references.section
180 if section then
181 sectiondata = sections.collected[section]
182 else
183 return pagedata, false, "no section"
184 end
185 end
186 if not sectiondata then
187 return pagedata, false, "no sectiondata"
188 end
189 local v_no = variables.no
190
191 if pagespecification and pagespecification.prefix == v_no then
192 return pagedata, false, "current spec blocks prefix"
193 end
194
195
196
197
198
199 pagespecification = pagedata.prefixdata
200 if pagespecification and pagespecification.prefix == v_no then
201 return pagedata, false, "pagedata blocks prefix"
202 end
203
204 return pagedata, sectiondata, "okay"
205end
206
207function helpers.page(data,pagespec)
208 if data then
209 local pagedata = pages.analyze(data,pagespec)
210 if pagedata then
211 pages.number(pagedata,pagespec)
212 end
213 end
214end
215
216function helpers.prefixpage(data,prefixspec,pagespec)
217 if data then
218 local pagedata, prefixdata, e = pages.analyze(data,pagespec)
219 if pagedata then
220 if prefixdata then
221 sections.typesetnumber(prefixdata,"prefix",prefixspec or false,prefixdata or false,pagedata.prefixdata or false)
222 end
223 pages.number(pagedata,pagespec)
224 end
225 end
226end
227
228function helpers.prefixlastpage(data,prefixspec,pagespec)
229 if data then
230 local r = data.references
231 local ls = r.section
232 local lr = r.realpage
233 r.section = r.lastsection or r.section
234 r.realpage = r.lastrealpage or r.realpage
235 helpers.prefixpage(data,prefixspec,pagespec)
236 r.section, r.realpage = ls, lr
237 end
238end
239
240
241
242function helpers.analyze(entry,specification)
243
244 if not entry then
245 return false, false, "no entry"
246 end
247 local yes = variables.yes
248 local no = variables.no
249
250 local references = entry.references
251 if not references then
252 return entry, false, "no references"
253 end
254 local section = references.section
255 if not section then
256 return entry, false, "no section"
257 end
258 local sectiondata = references.sectiondata or sections.collected[references.section]
259 if not sectiondata then
260 return entry, false, "no section data"
261 end
262
263 if specification and specification.prefix == no then
264 return entry, false, "current spec blocks prefix"
265 end
266
267 local prefixdata = entry.prefixdata
268 if prefixdata and prefixdata.prefix == no then
269 return entry, false, "entry blocks prefix"
270 end
271
272 return entry, sectiondata, "okay"
273end
274
275function helpers.prefix(data,prefixspec,nosuffix)
276 if data then
277 local _, prefixdata, status = helpers.analyze(data,prefixspec)
278 if prefixdata then
279 if nosuffix and prefixspec then
280 local connector = prefixspec.connector
281 prefixspec.connector = nil
282 sections.typesetnumber(prefixdata,"prefix",prefixspec or false,data.prefixdata or false,prefixdata or false)
283 prefixspec.connector = connector
284 else
285 sections.typesetnumber(prefixdata,"prefix",prefixspec or false,data.prefixdata or false,prefixdata or false)
286 end
287 end
288 end
289end
290
291function helpers.pageofinternal(n,prefixspec,pagespec)
292 local data = structures.references.internals[n]
293 if not data then
294
295 elseif prefixspec then
296 helpers.prefixpage(data,prefixspec,pagespec)
297 else
298 helpers.prefix(data,pagespec)
299 end
300end
301
302function pages.is_odd(n)
303 n = n or texgetcount("realpageno")
304 if texgetcount("pagenoshift") % 2 == 0 then
305 return n % 2 ~= 0
306 else
307 return n % 2 == 0
308 end
309end
310
311function pages.on_right(n)
312 local pagemode = texgetcount("pageduplexmode")
313 if pagemode == 2 or pagemode == 1 then
314 n = n or texgetcount("realpageno")
315 if texgetcount("pagenoshift") % 2 == 0 then
316 return n % 2 ~= 0
317 else
318 return n % 2 == 0
319 end
320 else
321 return true
322 end
323end
324
325function pages.in_body(n)
326 return texgetcount("pagebodymode") > 0
327end
328
329function pages.fraction(n)
330 local lastpage = texgetcount("lastpageno")
331 return lastpage > 1 and (texgetcount("realpageno")-1)/(lastpage-1) or 1
332end
333
334
335
336function counters.analyze(name,counterspecification)
337 local cd = counterdata[name]
338
339 if not cd then
340 return false, false, "no counter data"
341 end
342
343 local sectiondata = sections.current()
344 if not sectiondata then
345 return cd, false, "not in section"
346 end
347 local references = sectiondata.references
348 if not references then
349 return cd, false, "no references"
350 end
351 local section = references.section
352 if not section then
353 return cd, false, "no section"
354 end
355 sectiondata = sections.collected[references.section]
356 if not sectiondata then
357 return cd, false, "no section data"
358 end
359
360 local no = variables.no
361 if counterspecification and counterspecification.prefix == no then
362 return cd, false, "current spec blocks prefix"
363 end
364
365 if cd.prefix == no then
366 return cd, false, "entry blocks prefix"
367 end
368
369
370
371
372
373 return cd, sectiondata, "okay"
374end
375
376function sections.prefixedconverted(name,prefixspec,numberspec)
377 local cd, prefixdata, result = counters.analyze(name,prefixspec)
378 if cd then
379 if prefixdata then
380 sections.typesetnumber(prefixdata,"prefix",prefixspec or false,cd or false)
381 end
382 counters.converted(name,numberspec)
383 end
384end
385
386
387
388implement {
389 name = "savepagedata",
390 actions = pages.save,
391 arguments = {
392 {
393 { "prefix" },
394 { "separatorset" },
395 { "conversionset" },
396 { "conversion" },
397 { "set" },
398 { "segments" },
399 { "connector" },
400 },
401 {
402 { "conversionset" },
403 { "conversion" },
404 { "starter" },
405 { "stopper" },
406 },
407 {
408 { "viewerprefix" },
409 { "state" },
410 }
411 }
412}
413
414implement {
415 name = "prefixedconverted",
416 actions = sections.prefixedconverted,
417 arguments = {
418 "string",
419 {
420 { "prefix" },
421 { "separatorset" },
422 { "conversionset" },
423 { "conversion" },
424 { "starter" },
425 { "stopper" },
426 { "set" },
427 { "segments" },
428 { "connector" },
429 },
430 {
431 { "order" },
432 { "separatorset" },
433 { "conversionset" },
434 { "conversion" },
435 { "starter" },
436 { "stopper" },
437 { "segments" },
438 { "type" },
439 { "criterium" },
440 }
441 }
442}
443
444interfaces.implement {
445 name = "pageofinternal",
446 arguments = "integer",
447 actions = helpers.pageofinternal,
448}
449 |