diff options
author | Marius <mariausol@gmail.com> | 2013-05-19 20:40:34 +0300 |
---|---|---|
committer | Marius <mariausol@gmail.com> | 2013-05-19 20:40:34 +0300 |
commit | 13ec4b540e0d46c97fd7b089e0b7413da81e0a9f (patch) | |
tree | bebfa563a17c06b3bd3bf8f6f4ba6d025e00d107 /tex/context/base/strc-num.lua | |
parent | 69ad13650cda027526271179e95b5294694143a1 (diff) | |
download | context-13ec4b540e0d46c97fd7b089e0b7413da81e0a9f.tar.gz |
beta 2013.05.19 19:27
Diffstat (limited to 'tex/context/base/strc-num.lua')
-rw-r--r-- | tex/context/base/strc-num.lua | 1298 |
1 files changed, 649 insertions, 649 deletions
diff --git a/tex/context/base/strc-num.lua b/tex/context/base/strc-num.lua index b0eae6b78..6245a537e 100644 --- a/tex/context/base/strc-num.lua +++ b/tex/context/base/strc-num.lua @@ -1,649 +1,649 @@ -if not modules then modules = { } end modules ['strc-num'] = { - version = 1.001, - comment = "companion to strc-num.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local format = string.format -local next, type = next, type -local min, max = math.min, math.max -local texcount, texsetcount = tex.count, tex.setcount - --- Counters are managed here. They can have multiple levels which makes it easier to synchronize --- them. Synchronization is sort of special anyway, as it relates to document structuring. - -local allocate = utilities.storage.allocate -local setmetatableindex = table.setmetatableindex - -local trace_counters = false trackers.register("structures.counters", function(v) trace_counters = v end) -local report_counters = logs.reporter("structure","counters") - -local structures = structures -local helpers = structures.helpers -local sections = structures.sections -local counters = structures.counters -local documents = structures.documents - -local variables = interfaces.variables -local v_start = variables.start -local v_page = variables.page -local v_reverse = variables.reverse -local v_first = variables.first -local v_next = variables.next -local v_previous = variables.previous -local v_prev = variables.prev -local v_last = variables.last ------ v_no = variables.no -local v_backward = variables.backward -local v_forward = variables.forward ------ v_subs = variables.subs or "subs" - --- states: start stop none reset - --- specials are used for counters that are set and incremented in special ways, like --- pagecounters that get this treatment in the page builder - -counters.specials = counters.specials or { } -local counterspecials = counters.specials - -local counterranges, tbs = { }, 0 - -counters.collected = allocate() -counters.tobesaved = counters.tobesaved or { } -counters.data = counters.data or { } - -storage.register("structures/counters/data", counters.data, "structures.counters.data") -storage.register("structures/counters/tobesaved", counters.tobesaved, "structures.counters.tobesaved") - -local collected = counters.collected -local tobesaved = counters.tobesaved -local counterdata = counters.data - -local function initializer() -- not really needed - collected = counters.collected - tobesaved = counters.tobesaved - counterdata = counters.data -end - -local function finalizer() - for name, cd in next, counterdata do - local cs = tobesaved[name] - local data = cd.data - for i=1,#data do - local d = data[i] - local r = d.range - cs[i][r] = d.number - d.range = r + 1 - end - end -end - -job.register('structures.counters.collected', tobesaved, initializer, finalizer) - -local constructor = { -- maybe some day we will provide an installer for more variants - - last = function(t,name,i) - local cc = collected[name] - local stop = (cc and cc[i] and cc[i][t.range]) or 0 -- stop is available for diagnostics purposes only - t.stop = stop - if t.offset then - return stop - t.step - else - return stop - end - end, - - first = function(t,name,i) - local start = t.start - if start > 0 then - return start -- brrr - elseif t.offset then - return start + t.step + 1 - else - return start + 1 - end - end, - - prev = function(t,name,i) - return max(t.first,t.number-1) -- todo: step - end, - - previous = function(t,name,i) - return max(t.first,t.number-1) -- todo: step - end, - - next = function(t,name,i) - return min(t.last,t.number+1) -- todo: step - end, - - backward =function(t,name,i) - if t.number - 1 < t.first then - return t.last - else - return t.previous - end - end, - - forward = function(t,name,i) - if t.number + 1 > t.last then - return t.first - else - return t.next - end - end, - - subs = function(t,name,i) - local cc = collected[name] - t.subs = (cc and cc[i+1] and cc[i+1][t.range]) or 0 - return t.subs - end, - -} - -local function dummyconstructor(t,name,i) - return nil -- was 0, but that is fuzzy in testing for e.g. own -end - -setmetatableindex(constructor,function(t,k) - if trace_counters then - report_counters("unknown constructor %a",k) - end - return dummyconstructor -end) - -local function enhance() - for name, cd in next, counterdata do - local data = cd.data - for i=1,#data do - local ci = data[i] - setmetatableindex(ci, function(t,s) return constructor[s](t,name,i) end) - end - end - enhance = nil -end - -local function allocate(name,i) -- can be metatable - local cd = counterdata[name] - if not cd then - cd = { - level = 1, - -- block = "", -- todo - numbers = nil, - state = v_start, -- true - data = { }, - saved = { }, - } - tobesaved[name] = { } - counterdata[name] = cd - end - cd = cd.data - local ci = cd[i] - if not ci then - ci = { - number = 0, - start = 0, - saved = 0, - step = 1, - range = 1, - offset = false, - stop = 0, -- via metatable: last, first, stop only for tracing - } - setmetatableindex(ci, function(t,s) return constructor[s](t,name,i) end) - cd[i] = ci - tobesaved[name][i] = { } - else - if enhance then enhance() end -- not stored in bytecode - end - return ci -end - -function counters.record(name,i) - return allocate(name,i or 1) -end - -local function savevalue(name,i) - if name then - local cd = counterdata[name].data[i] - local cs = tobesaved[name][i] - local cc = collected[name] - if trace_counters then - report_counters("action %a, counter %s, value %s","save",name,cd.number) - end - local cr = cd.range - local old = (cc and cc[i] and cc[i][cr]) or 0 - local number = cd.number - if cd.method == v_page then - -- we can be one page ahead - number = number - 1 - end - cs[cr] = (number >= 0) and number or 0 - cd.range = cr + 1 - return old - else - return 0 - end -end - -function counters.define(specification) - local name = specification.name - if name and name ~= "" then - -- todo: step - local d = allocate(name,1) - d.start = tonumber(specification.start) or 0 - d.state = v_state or "" - local counter = specification.counter - if counter and counter ~= "" then - d.counter = counter -- only for special purposes, cannot be false - d.method = specification.method -- frozen at define time - end - end -end - -function counters.raw(name) - return counterdata[name] -end - -function counters.compact(name,level,onlynumbers) - local cd = counterdata[name] - if cd then - local data = cd.data - local compact = { } - for i=1,level or #data do - local d = data[i] - if d.number ~= 0 then - compact[i] = (onlynumbers and d.number) or d - end - end - return compact - end -end - --- depends on when incremented, before or after (driven by d.offset) - -function counters.previous(name,n) - return allocate(name,n).previous -end - -function counters.next(name,n) - return allocate(name,n).next -end - -counters.prev = counters.previous - -function counters.currentvalue(name,n) - return allocate(name,n).number -end - -function counters.first(name,n) - return allocate(name,n).first -end - -function counters.last(name,n) - return allocate(name,n).last -end - -function counters.subs(name,n) - return counterdata[name].data[n].subs or 0 -end - -local function setvalue(name,tag,value) - local cd = counterdata[name] - if cd then - cd[tag] = value - end -end - -counters.setvalue = setvalue - -function counters.setstate(name,value) -- true/false - value = variables[value] - if value then - setvalue(name,"state",value) - end -end - -function counters.setlevel(name,value) - setvalue(name,"level",value) -end - -function counters.setoffset(name,value) - setvalue(name,"offset",value) -end - -local function synchronize(name,d) - local dc = d.counter - if dc then - if trace_counters then - report_counters("action %a, name %a, counter %a, value %a","synchronize",name,dc,d.number) - end - texsetcount("global",dc,d.number) - end - local cs = counterspecials[name] - if cs then - if trace_counters then - report_counters("action %a, name %a, counter %a","synccommand",name,dc) - end - cs(name) - end -end - -local function reset(name,n) - local cd = counterdata[name] - if cd then - for i=n or 1,#cd.data do - local d = cd.data[i] - savevalue(name,i) - local number = d.start or 0 - d.number = number - d.own = nil - if trace_counters then - report_counters("action %a, name %a, sub %a, value %a","reset",name,i,number) - end - synchronize(name,d) - end - cd.numbers = nil - else - end -end - -local function set(name,n,value) - local cd = counterdata[name] - if cd then - local d = allocate(name,n) - local number = value or 0 - d.number = number - d.own = nil - if trace_counters then - report_counters("action %a, name %a, sub %a, value %a","set",name,"no",number) - end - synchronize(name,d) - end -end - -local function check(name,data,start,stop) - for i=start or 1,stop or #data do - local d = data[i] - savevalue(name,i) - local number = d.start or 0 - d.number = number - d.own = nil - if trace_counters then - report_counters("action %a, name %a, sub %a, value %a","check",name,i,number) - end - synchronize(name,d) - end -end - -counters.reset = reset -counters.set = set - -function counters.setown(name,n,value) - local cd = counterdata[name] - if cd then - local d = allocate(name,n) - d.own = value - d.number = (d.number or d.start or 0) + (d.step or 0) - local level = cd.level - if not level or level == -1 then - -- -1 is signal that we reset manually - elseif level > 0 or level == -3 then - check(name,d,n+1) - elseif level == 0 then - -- happens elsewhere, check this for block - end - synchronize(name,d) - end -end - -function counters.restart(name,n,newstart,noreset) - local cd = counterdata[name] - if cd then - newstart = tonumber(newstart) - if newstart then - local d = allocate(name,n) - d.start = newstart - if not noreset then - reset(name,n) -- hm - end - end - end -end - -function counters.save(name) -- or just number - local cd = counterdata[name] - if cd then - table.insert(cd.saved,table.copy(cd.data)) - end -end - -function counters.restore(name) - local cd = counterdata[name] - if cd and cd.saved then - cd.data = table.remove(cd.saved) - end -end - -function counters.add(name,n,delta) - local cd = counterdata[name] - if cd and (cd.state == v_start or cd.state == "") then - local data = cd.data - local d = allocate(name,n) - d.number = (d.number or d.start or 0) + delta*(d.step or 0) - -- d.own = nil - local level = cd.level - if not level or level == -1 then - -- -1 is signal that we reset manually - if trace_counters then - report_counters("action %a, name %a, sub %a, how %a","add",name,"no","no checking") - end - elseif level == -2 then - -- -2 is signal that we work per text - if trace_counters then - report_counters("action %a, name %a, sub %a, how %a","add",name,"text","checking") - end - check(name,data,n+1) - elseif level > 0 or level == -3 then - -- within countergroup - if trace_counters then - report_counters("action %a, name %a, sub %a, how %a","add",name,level,"checking within group") - end - check(name,data,n+1) - elseif level == 0 then - -- happens elsewhere - if trace_counters then - report_counters("action %a, name %a, sub %a, how %a","add",name,level,"no checking") - end - else - if trace_counters then - report_counters("action %a, name %a, sub %a, how %a","add",name,"unknown","no checking") - end - end - synchronize(name,d) - return d.number -- not needed - end - return 0 -end - -function counters.check(level) - for name, cd in next, counterdata do - if level > 0 and cd.level == -3 then -- could become an option - if trace_counters then - report_counters("action %a, name %a, sub %a, detail %a","reset",name,level,"head") - end - reset(name) - elseif cd.level == level then - if trace_counters then - report_counters("action %a, name %a, sub %a, detail %a","reset",name,level,"normal") - end - reset(name) - end - end -end - -local function get(name,n,key) - local d = allocate(name,n) - d = d and d[key] - if not d then - return 0 - elseif type(d) == "function" then - return d() - else - return d - end -end - -counters.get = get - -function counters.value(name,n) -- what to do with own - return get(name,n or 1,'number') or 0 -end - -function counters.converted(name,spec) -- name can be number and reference to storage - local cd - if type(name) == "number" then - cd = specials.retrieve("counter",name) - cd = cd and cd.counter - else - cd = counterdata[name] - end - if cd then - local spec = spec or { } - local numbers, ownnumbers = { }, { } - local reverse = spec.order == v_reverse - local kind = spec.type or "number" - local data = cd.data - for k=1,#data do - local v = data[k] - -- somewhat messy, what if subnr? only last must honour kind? - local vn - if v.own then - numbers[k], ownnumbers[k] = v.number, v.own - else - if kind == v_first then - vn = v.first - elseif kind == v_next then - vn = v.next - elseif kind == v_prev or kind == v_previous then - vn = v.prev - elseif kind == v_last then - vn = v.last - else - vn = v.number - if reverse then - local vf = v.first - local vl = v.last - if vl > 0 then - -- vn = vl - vn + 1 + vf - vn = vl - vn + vf -- see testbed for test - end - end - end - numbers[k], ownnumbers[k] = vn or v.number, nil - end - end - cd.numbers = numbers - cd.ownnumbers = ownnumbers - sections.typesetnumber(cd,'number',spec) - cd.numbers = nil - cd.ownnumbers = nil - end -end - --- interfacing - -commands.definecounter = counters.define -commands.setcounter = counters.set -commands.setowncounter = counters.setown -commands.resetcounter = counters.reset -commands.restartcounter = counters.restart -commands.savecounter = counters.save -commands.restorecounter = counters.restore -commands.addcounter = counters.add - -commands.rawcountervalue = function(...) context(counters.raw (...)) end -commands.countervalue = function(...) context(counters.value (...)) end -commands.lastcountervalue = function(...) context(counters.last (...)) end -commands.firstcountervalue = function(...) context(counters.first (...)) end -commands.nextcountervalue = function(...) context(counters.next (...)) end -commands.prevcountervalue = function(...) context(counters.previous(...)) end -commands.subcountervalues = function(...) context(counters.subs (...)) end - -function commands.showcounter(name) - local cd = counterdata[name] - if cd then - context("[%s:",name) - local data = cd.data - for i=1,#data do - local d = data[i] - context(" (%s: %s,%s,%s s:%s r:%s)",i,d.start or 0,d.number or 0,d.last,d.step or 0,d.range or 0) - end - context("]") - end -end - -function commands.doifelsecounter(name) commands.doifelse(counterdata[name]) end -function commands.doifcounter (name) commands.doif (counterdata[name]) end -function commands.doifnotcounter (name) commands.doifnot (counterdata[name]) end - -function commands.incrementedcounter(...) context(counters.add(...)) end - -function commands.checkcountersetup(name,level,start,state) - counters.restart(name,1,start,true) -- no reset - counters.setstate(name,state) - counters.setlevel(name,level) - sections.setchecker(name,level,counters.reset) -end - --- -- move to strc-pag.lua --- --- function counters.analyze(name,counterspecification) --- local cd = counterdata[name] --- -- safeguard --- if not cd then --- return false, false, "no counter data" --- end --- -- section data --- local sectiondata = sections.current() --- if not sectiondata then --- return cd, false, "not in section" --- end --- local references = sectiondata.references --- if not references then --- return cd, false, "no references" --- end --- local section = references.section --- if not section then --- return cd, false, "no section" --- end --- sectiondata = sections.collected[references.section] --- if not sectiondata then --- return cd, false, "no section data" --- end --- -- local preferences --- local no = v_no --- if counterspecification and counterspecification.prefix == no then --- return cd, false, "current spec blocks prefix" --- end --- -- stored preferences (not used) --- if cd.prefix == no then --- return cd, false, "entry blocks prefix" --- end --- -- sectioning --- -- if sectiondata.prefix == no then --- -- return false, false, "sectiondata blocks prefix" --- -- end --- -- final verdict --- return cd, sectiondata, "okay" --- end --- --- function counters.prefixedconverted(name,prefixspec,numberspec) --- local cd, prefixdata, result = counters.analyze(name,prefixspec) --- if cd then --- if prefixdata then --- sections.typesetnumber(prefixdata,"prefix",prefixspec or false,cd or false) --- end --- counters.converted(name,numberspec) --- end --- end +if not modules then modules = { } end modules ['strc-num'] = {
+ version = 1.001,
+ comment = "companion to strc-num.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+local next, type = next, type
+local min, max = math.min, math.max
+local texcount, texsetcount = tex.count, tex.setcount
+
+-- Counters are managed here. They can have multiple levels which makes it easier to synchronize
+-- them. Synchronization is sort of special anyway, as it relates to document structuring.
+
+local allocate = utilities.storage.allocate
+local setmetatableindex = table.setmetatableindex
+
+local trace_counters = false trackers.register("structures.counters", function(v) trace_counters = v end)
+local report_counters = logs.reporter("structure","counters")
+
+local structures = structures
+local helpers = structures.helpers
+local sections = structures.sections
+local counters = structures.counters
+local documents = structures.documents
+
+local variables = interfaces.variables
+local v_start = variables.start
+local v_page = variables.page
+local v_reverse = variables.reverse
+local v_first = variables.first
+local v_next = variables.next
+local v_previous = variables.previous
+local v_prev = variables.prev
+local v_last = variables.last
+----- v_no = variables.no
+local v_backward = variables.backward
+local v_forward = variables.forward
+----- v_subs = variables.subs or "subs"
+
+-- states: start stop none reset
+
+-- specials are used for counters that are set and incremented in special ways, like
+-- pagecounters that get this treatment in the page builder
+
+counters.specials = counters.specials or { }
+local counterspecials = counters.specials
+
+local counterranges, tbs = { }, 0
+
+counters.collected = allocate()
+counters.tobesaved = counters.tobesaved or { }
+counters.data = counters.data or { }
+
+storage.register("structures/counters/data", counters.data, "structures.counters.data")
+storage.register("structures/counters/tobesaved", counters.tobesaved, "structures.counters.tobesaved")
+
+local collected = counters.collected
+local tobesaved = counters.tobesaved
+local counterdata = counters.data
+
+local function initializer() -- not really needed
+ collected = counters.collected
+ tobesaved = counters.tobesaved
+ counterdata = counters.data
+end
+
+local function finalizer()
+ for name, cd in next, counterdata do
+ local cs = tobesaved[name]
+ local data = cd.data
+ for i=1,#data do
+ local d = data[i]
+ local r = d.range
+ cs[i][r] = d.number
+ d.range = r + 1
+ end
+ end
+end
+
+job.register('structures.counters.collected', tobesaved, initializer, finalizer)
+
+local constructor = { -- maybe some day we will provide an installer for more variants
+
+ last = function(t,name,i)
+ local cc = collected[name]
+ local stop = (cc and cc[i] and cc[i][t.range]) or 0 -- stop is available for diagnostics purposes only
+ t.stop = stop
+ if t.offset then
+ return stop - t.step
+ else
+ return stop
+ end
+ end,
+
+ first = function(t,name,i)
+ local start = t.start
+ if start > 0 then
+ return start -- brrr
+ elseif t.offset then
+ return start + t.step + 1
+ else
+ return start + 1
+ end
+ end,
+
+ prev = function(t,name,i)
+ return max(t.first,t.number-1) -- todo: step
+ end,
+
+ previous = function(t,name,i)
+ return max(t.first,t.number-1) -- todo: step
+ end,
+
+ next = function(t,name,i)
+ return min(t.last,t.number+1) -- todo: step
+ end,
+
+ backward =function(t,name,i)
+ if t.number - 1 < t.first then
+ return t.last
+ else
+ return t.previous
+ end
+ end,
+
+ forward = function(t,name,i)
+ if t.number + 1 > t.last then
+ return t.first
+ else
+ return t.next
+ end
+ end,
+
+ subs = function(t,name,i)
+ local cc = collected[name]
+ t.subs = (cc and cc[i+1] and cc[i+1][t.range]) or 0
+ return t.subs
+ end,
+
+}
+
+local function dummyconstructor(t,name,i)
+ return nil -- was 0, but that is fuzzy in testing for e.g. own
+end
+
+setmetatableindex(constructor,function(t,k)
+ if trace_counters then
+ report_counters("unknown constructor %a",k)
+ end
+ return dummyconstructor
+end)
+
+local function enhance()
+ for name, cd in next, counterdata do
+ local data = cd.data
+ for i=1,#data do
+ local ci = data[i]
+ setmetatableindex(ci, function(t,s) return constructor[s](t,name,i) end)
+ end
+ end
+ enhance = nil
+end
+
+local function allocate(name,i) -- can be metatable
+ local cd = counterdata[name]
+ if not cd then
+ cd = {
+ level = 1,
+ -- block = "", -- todo
+ numbers = nil,
+ state = v_start, -- true
+ data = { },
+ saved = { },
+ }
+ tobesaved[name] = { }
+ counterdata[name] = cd
+ end
+ cd = cd.data
+ local ci = cd[i]
+ if not ci then
+ ci = {
+ number = 0,
+ start = 0,
+ saved = 0,
+ step = 1,
+ range = 1,
+ offset = false,
+ stop = 0, -- via metatable: last, first, stop only for tracing
+ }
+ setmetatableindex(ci, function(t,s) return constructor[s](t,name,i) end)
+ cd[i] = ci
+ tobesaved[name][i] = { }
+ else
+ if enhance then enhance() end -- not stored in bytecode
+ end
+ return ci
+end
+
+function counters.record(name,i)
+ return allocate(name,i or 1)
+end
+
+local function savevalue(name,i)
+ if name then
+ local cd = counterdata[name].data[i]
+ local cs = tobesaved[name][i]
+ local cc = collected[name]
+ if trace_counters then
+ report_counters("action %a, counter %s, value %s","save",name,cd.number)
+ end
+ local cr = cd.range
+ local old = (cc and cc[i] and cc[i][cr]) or 0
+ local number = cd.number
+ if cd.method == v_page then
+ -- we can be one page ahead
+ number = number - 1
+ end
+ cs[cr] = (number >= 0) and number or 0
+ cd.range = cr + 1
+ return old
+ else
+ return 0
+ end
+end
+
+function counters.define(specification)
+ local name = specification.name
+ if name and name ~= "" then
+ -- todo: step
+ local d = allocate(name,1)
+ d.start = tonumber(specification.start) or 0
+ d.state = v_state or ""
+ local counter = specification.counter
+ if counter and counter ~= "" then
+ d.counter = counter -- only for special purposes, cannot be false
+ d.method = specification.method -- frozen at define time
+ end
+ end
+end
+
+function counters.raw(name)
+ return counterdata[name]
+end
+
+function counters.compact(name,level,onlynumbers)
+ local cd = counterdata[name]
+ if cd then
+ local data = cd.data
+ local compact = { }
+ for i=1,level or #data do
+ local d = data[i]
+ if d.number ~= 0 then
+ compact[i] = (onlynumbers and d.number) or d
+ end
+ end
+ return compact
+ end
+end
+
+-- depends on when incremented, before or after (driven by d.offset)
+
+function counters.previous(name,n)
+ return allocate(name,n).previous
+end
+
+function counters.next(name,n)
+ return allocate(name,n).next
+end
+
+counters.prev = counters.previous
+
+function counters.currentvalue(name,n)
+ return allocate(name,n).number
+end
+
+function counters.first(name,n)
+ return allocate(name,n).first
+end
+
+function counters.last(name,n)
+ return allocate(name,n).last
+end
+
+function counters.subs(name,n)
+ return counterdata[name].data[n].subs or 0
+end
+
+local function setvalue(name,tag,value)
+ local cd = counterdata[name]
+ if cd then
+ cd[tag] = value
+ end
+end
+
+counters.setvalue = setvalue
+
+function counters.setstate(name,value) -- true/false
+ value = variables[value]
+ if value then
+ setvalue(name,"state",value)
+ end
+end
+
+function counters.setlevel(name,value)
+ setvalue(name,"level",value)
+end
+
+function counters.setoffset(name,value)
+ setvalue(name,"offset",value)
+end
+
+local function synchronize(name,d)
+ local dc = d.counter
+ if dc then
+ if trace_counters then
+ report_counters("action %a, name %a, counter %a, value %a","synchronize",name,dc,d.number)
+ end
+ texsetcount("global",dc,d.number)
+ end
+ local cs = counterspecials[name]
+ if cs then
+ if trace_counters then
+ report_counters("action %a, name %a, counter %a","synccommand",name,dc)
+ end
+ cs(name)
+ end
+end
+
+local function reset(name,n)
+ local cd = counterdata[name]
+ if cd then
+ for i=n or 1,#cd.data do
+ local d = cd.data[i]
+ savevalue(name,i)
+ local number = d.start or 0
+ d.number = number
+ d.own = nil
+ if trace_counters then
+ report_counters("action %a, name %a, sub %a, value %a","reset",name,i,number)
+ end
+ synchronize(name,d)
+ end
+ cd.numbers = nil
+ else
+ end
+end
+
+local function set(name,n,value)
+ local cd = counterdata[name]
+ if cd then
+ local d = allocate(name,n)
+ local number = value or 0
+ d.number = number
+ d.own = nil
+ if trace_counters then
+ report_counters("action %a, name %a, sub %a, value %a","set",name,"no",number)
+ end
+ synchronize(name,d)
+ end
+end
+
+local function check(name,data,start,stop)
+ for i=start or 1,stop or #data do
+ local d = data[i]
+ savevalue(name,i)
+ local number = d.start or 0
+ d.number = number
+ d.own = nil
+ if trace_counters then
+ report_counters("action %a, name %a, sub %a, value %a","check",name,i,number)
+ end
+ synchronize(name,d)
+ end
+end
+
+counters.reset = reset
+counters.set = set
+
+function counters.setown(name,n,value)
+ local cd = counterdata[name]
+ if cd then
+ local d = allocate(name,n)
+ d.own = value
+ d.number = (d.number or d.start or 0) + (d.step or 0)
+ local level = cd.level
+ if not level or level == -1 then
+ -- -1 is signal that we reset manually
+ elseif level > 0 or level == -3 then
+ check(name,d,n+1)
+ elseif level == 0 then
+ -- happens elsewhere, check this for block
+ end
+ synchronize(name,d)
+ end
+end
+
+function counters.restart(name,n,newstart,noreset)
+ local cd = counterdata[name]
+ if cd then
+ newstart = tonumber(newstart)
+ if newstart then
+ local d = allocate(name,n)
+ d.start = newstart
+ if not noreset then
+ reset(name,n) -- hm
+ end
+ end
+ end
+end
+
+function counters.save(name) -- or just number
+ local cd = counterdata[name]
+ if cd then
+ table.insert(cd.saved,table.copy(cd.data))
+ end
+end
+
+function counters.restore(name)
+ local cd = counterdata[name]
+ if cd and cd.saved then
+ cd.data = table.remove(cd.saved)
+ end
+end
+
+function counters.add(name,n,delta)
+ local cd = counterdata[name]
+ if cd and (cd.state == v_start or cd.state == "") then
+ local data = cd.data
+ local d = allocate(name,n)
+ d.number = (d.number or d.start or 0) + delta*(d.step or 0)
+ -- d.own = nil
+ local level = cd.level
+ if not level or level == -1 then
+ -- -1 is signal that we reset manually
+ if trace_counters then
+ report_counters("action %a, name %a, sub %a, how %a","add",name,"no","no checking")
+ end
+ elseif level == -2 then
+ -- -2 is signal that we work per text
+ if trace_counters then
+ report_counters("action %a, name %a, sub %a, how %a","add",name,"text","checking")
+ end
+ check(name,data,n+1)
+ elseif level > 0 or level == -3 then
+ -- within countergroup
+ if trace_counters then
+ report_counters("action %a, name %a, sub %a, how %a","add",name,level,"checking within group")
+ end
+ check(name,data,n+1)
+ elseif level == 0 then
+ -- happens elsewhere
+ if trace_counters then
+ report_counters("action %a, name %a, sub %a, how %a","add",name,level,"no checking")
+ end
+ else
+ if trace_counters then
+ report_counters("action %a, name %a, sub %a, how %a","add",name,"unknown","no checking")
+ end
+ end
+ synchronize(name,d)
+ return d.number -- not needed
+ end
+ return 0
+end
+
+function counters.check(level)
+ for name, cd in next, counterdata do
+ if level > 0 and cd.level == -3 then -- could become an option
+ if trace_counters then
+ report_counters("action %a, name %a, sub %a, detail %a","reset",name,level,"head")
+ end
+ reset(name)
+ elseif cd.level == level then
+ if trace_counters then
+ report_counters("action %a, name %a, sub %a, detail %a","reset",name,level,"normal")
+ end
+ reset(name)
+ end
+ end
+end
+
+local function get(name,n,key)
+ local d = allocate(name,n)
+ d = d and d[key]
+ if not d then
+ return 0
+ elseif type(d) == "function" then
+ return d()
+ else
+ return d
+ end
+end
+
+counters.get = get
+
+function counters.value(name,n) -- what to do with own
+ return get(name,n or 1,'number') or 0
+end
+
+function counters.converted(name,spec) -- name can be number and reference to storage
+ local cd
+ if type(name) == "number" then
+ cd = specials.retrieve("counter",name)
+ cd = cd and cd.counter
+ else
+ cd = counterdata[name]
+ end
+ if cd then
+ local spec = spec or { }
+ local numbers, ownnumbers = { }, { }
+ local reverse = spec.order == v_reverse
+ local kind = spec.type or "number"
+ local data = cd.data
+ for k=1,#data do
+ local v = data[k]
+ -- somewhat messy, what if subnr? only last must honour kind?
+ local vn
+ if v.own then
+ numbers[k], ownnumbers[k] = v.number, v.own
+ else
+ if kind == v_first then
+ vn = v.first
+ elseif kind == v_next then
+ vn = v.next
+ elseif kind == v_prev or kind == v_previous then
+ vn = v.prev
+ elseif kind == v_last then
+ vn = v.last
+ else
+ vn = v.number
+ if reverse then
+ local vf = v.first
+ local vl = v.last
+ if vl > 0 then
+ -- vn = vl - vn + 1 + vf
+ vn = vl - vn + vf -- see testbed for test
+ end
+ end
+ end
+ numbers[k], ownnumbers[k] = vn or v.number, nil
+ end
+ end
+ cd.numbers = numbers
+ cd.ownnumbers = ownnumbers
+ sections.typesetnumber(cd,'number',spec)
+ cd.numbers = nil
+ cd.ownnumbers = nil
+ end
+end
+
+-- interfacing
+
+commands.definecounter = counters.define
+commands.setcounter = counters.set
+commands.setowncounter = counters.setown
+commands.resetcounter = counters.reset
+commands.restartcounter = counters.restart
+commands.savecounter = counters.save
+commands.restorecounter = counters.restore
+commands.addcounter = counters.add
+
+commands.rawcountervalue = function(...) context(counters.raw (...)) end
+commands.countervalue = function(...) context(counters.value (...)) end
+commands.lastcountervalue = function(...) context(counters.last (...)) end
+commands.firstcountervalue = function(...) context(counters.first (...)) end
+commands.nextcountervalue = function(...) context(counters.next (...)) end
+commands.prevcountervalue = function(...) context(counters.previous(...)) end
+commands.subcountervalues = function(...) context(counters.subs (...)) end
+
+function commands.showcounter(name)
+ local cd = counterdata[name]
+ if cd then
+ context("[%s:",name)
+ local data = cd.data
+ for i=1,#data do
+ local d = data[i]
+ context(" (%s: %s,%s,%s s:%s r:%s)",i,d.start or 0,d.number or 0,d.last,d.step or 0,d.range or 0)
+ end
+ context("]")
+ end
+end
+
+function commands.doifelsecounter(name) commands.doifelse(counterdata[name]) end
+function commands.doifcounter (name) commands.doif (counterdata[name]) end
+function commands.doifnotcounter (name) commands.doifnot (counterdata[name]) end
+
+function commands.incrementedcounter(...) context(counters.add(...)) end
+
+function commands.checkcountersetup(name,level,start,state)
+ counters.restart(name,1,start,true) -- no reset
+ counters.setstate(name,state)
+ counters.setlevel(name,level)
+ sections.setchecker(name,level,counters.reset)
+end
+
+-- -- move to strc-pag.lua
+--
+-- function counters.analyze(name,counterspecification)
+-- local cd = counterdata[name]
+-- -- safeguard
+-- if not cd then
+-- return false, false, "no counter data"
+-- end
+-- -- section data
+-- local sectiondata = sections.current()
+-- if not sectiondata then
+-- return cd, false, "not in section"
+-- end
+-- local references = sectiondata.references
+-- if not references then
+-- return cd, false, "no references"
+-- end
+-- local section = references.section
+-- if not section then
+-- return cd, false, "no section"
+-- end
+-- sectiondata = sections.collected[references.section]
+-- if not sectiondata then
+-- return cd, false, "no section data"
+-- end
+-- -- local preferences
+-- local no = v_no
+-- if counterspecification and counterspecification.prefix == no then
+-- return cd, false, "current spec blocks prefix"
+-- end
+-- -- stored preferences (not used)
+-- if cd.prefix == no then
+-- return cd, false, "entry blocks prefix"
+-- end
+-- -- sectioning
+-- -- if sectiondata.prefix == no then
+-- -- return false, false, "sectiondata blocks prefix"
+-- -- end
+-- -- final verdict
+-- return cd, sectiondata, "okay"
+-- end
+--
+-- function counters.prefixedconverted(name,prefixspec,numberspec)
+-- local cd, prefixdata, result = counters.analyze(name,prefixspec)
+-- if cd then
+-- if prefixdata then
+-- sections.typesetnumber(prefixdata,"prefix",prefixspec or false,cd or false)
+-- end
+-- counters.converted(name,numberspec)
+-- end
+-- end
|