bibl-tra.lua /size: 9883 b    last modification: 2020-07-01 14:35
1if not modules then modules = { } end modules ['bibl-tra'] = {
2    version   = 1.001,
3    comment   = "this module is the basis for the lxml-* ones",
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-- also see bibl-tra-new !
10
11-- temporary hack, needed for transition
12
13if not publications then
14
15    local hacks = utilities.storage.allocate()
16
17    job.register('publications.collected',hacks,function(t) publications.collected = t end)
18
19end
20
21-- end of hack
22
23
24local gmatch, format = string.gmatch, string.format
25local sort = table.sort
26local savedata = io.savedata
27
28bibtex       = bibtex or { }
29local bibtex = bibtex
30
31bibtex.hacks = bibtex.hacks or { }
32local hacks  = bibtex.hacks
33
34local trace_bibtex = false  trackers.register("publications.bibtex", function(v) trace_bibtex = v end)
35
36local report_tex = logs.reporter("publications","tex")
37
38local context     = context
39local structures  = structures
40
41local references  = structures.references
42local sections    = structures.sections
43
44local variables   = interfaces.variables
45
46local v_short     = variables.short
47local v_cite      = variables.cite
48local v_default   = variables.default
49local v_reference = variables.default
50
51local list        = { }
52local done        = { }
53local alldone     = { }
54local used        = { }
55local registered  = { }
56local ordered     = { }
57local shorts      = { }
58local mode        = 0
59
60local template = [[
61\citation{*}
62\bibstyle{cont-%s}
63\bibdata{%s}
64]]
65
66local runners = {
67    bibtex = sandbox.registerrunner {
68        name     = "bibtex",
69        method   = "execute",
70        program  = "bibtex",
71        template = "%filename%",
72        checkers = {
73            filename = "readable",
74        }
75    },
76    mlbibtex = sandbox.registerrunner {
77        name     = "mlbibtex",
78        method   = "execute",
79        program  = "mlbibcontext",
80        template = "%filename%",
81        checkers = {
82            filename = "readable",
83        }
84    }
85}
86
87local runner = environment.arguments.mlbibtex and runners.mlbibtex or runners.bibtex
88
89directives.register("publications.usemlbibtex", function(v)
90    runner = v and runners.mlbibtex or runners.bibtex
91end)
92
93function hacks.process(settings)
94    local style = settings.style or ""
95    local database = settings.database or ""
96    local jobname = tex.jobname
97    if database ~= "" then
98        local targetfile = file.addsuffix(jobname,"aux")
99        interfaces.showmessage("publications",3,targetfile)
100        savedata(targetfile,format(template,style,database))
101        if trace_bibtex then
102            report_tex("processing bibtex file %a using %a",jobname,bibtexbin)
103        end
104        runner { filename = jobname }
105        -- purge 'm
106    end
107end
108
109function hacks.register(tag,short)
110    if not short or short == "" then
111        short = tag
112    end
113    if trace_bibtex then
114        report_tex("registering bibtex entry %a with shortcut %a",tag,short)
115    end
116    local top = #registered + 1
117    registered[top] = tag
118    ordered   [tag] = top
119    shorts    [tag] = short
120end
121
122function hacks.nofregistered()
123    return #registered
124end
125
126function hacks.reset(m)
127    mode, list, done = m, { }, { }
128end
129
130function hacks.add(str,listindex)
131    if not str or mode == 0 then
132        -- skip
133    elseif mode == 1 then
134        -- all locals but no duplicates
135        local sc = sections.currentid()
136        if done[str] ~= sc then
137            done[str], alldone[str] = sc, true
138            list[#list+1] = { str, listindex }
139        end
140    elseif mode == 2 then
141        -- all locals but no preceding
142        local sc = sections.currentid()
143        if not alldone[str] and done[str] ~= sc then
144            done[str], alldone[str] = sc, true
145            list[#list+1] = { str, listindex }
146        end
147    end
148end
149
150function hacks.flush(sortvariant)
151    local compare -- quite some checking for non-nil
152    if sortvariant == "" or sortvariant == v_cite or sortvariant == v_default then
153        -- order is cite order i.e. same as list
154    elseif sortvariant == v_short then
155        compare = function(a,b)
156            local aa, bb = a and a[1], b and b[1]
157            if aa and bb then
158                local oa, ob = shorts[aa], shorts[bb]
159                return oa and ob and oa < ob
160            end
161            return false
162        end
163    elseif sortvariant == v_reference then
164        compare = function(a,b)
165            local aa, bb = a and a[1], b and b[1]
166            if aa and bb then
167                return aa and bb and aa < bb
168            end
169            return false
170        end
171    else
172        compare = function(a,b)
173            local aa, bb = a and a[1], b and b[1]
174            if aa and bb then
175                local oa, ob = ordered[aa], ordered[bb]
176                return oa and ob and oa < ob
177            end
178            return false
179        end
180    end
181    if compare then
182        sort(list,compare)
183    end
184    for i=1,#list do
185        context.doprocessbibtexentry(list[i][1])
186    end
187end
188
189function hacks.filterall()
190    for i=1,#registered do
191        list[i] = { registered[i], i }
192    end
193end
194
195function hacks.registerplaced(str)
196    used[str] = true
197end
198
199function hacks.doifalreadyplaced(str)
200    commands.doifelse(used[str])
201end
202
203-- we ask for <n>:tag but when we can't find it we go back
204-- to look for previous definitions, and when not found again
205-- we look forward
206
207local function compare(a,b)
208    local aa, bb = a and a[3], b and b[3]
209    return aa and bb and aa < bb
210end
211
212function hacks.resolve(prefix,block,reference) -- maybe already feed it split
213    -- needs checking (the prefix in relation to components)
214    local subsets
215    local collected = references.collected
216    if prefix and prefix ~= "" then
217        subsets = { collected[prefix] or collected[""] }
218    else
219        local components = references.productdata.components
220        local subset = collected[""]
221        if subset then
222            subsets = { subset }
223        else
224            subsets = { }
225        end
226        for i=1,#components do
227            local subset = collected[components[i]]
228            if subset then
229                subsets[#subsets+1] = subset
230            end
231        end
232    end
233    if #subsets > 0 then
234        local result, nofresult, done = { }, 0, { }
235        block = tonumber(block)
236        for i=1,#subsets do
237            local subset = subsets[i]
238            for rest in gmatch(reference,"[^, ]+") do
239                local blk, tag, found = block, nil, nil
240                if block then
241                    tag = blk .. ":" .. rest
242                    found = subset[tag]
243                    if not found then
244                        for i=block-1,1,-1 do
245                            tag = i .. ":" .. rest
246                            found = subset[tag]
247                            if found then
248                                blk = i
249                                break
250                            end
251                        end
252                    end
253                end
254                if not found then
255                    blk = "*"
256                    tag = blk .. ":" .. rest
257                    found = subset[tag]
258                end
259                if found then
260                    local current = tonumber(found.entries and found.entries.text) -- tonumber needed
261                    if current and not done[current] then
262                        nofresult = nofresult + 1
263                        result[nofresult] = { blk, rest, current }
264                        done[current] = true
265                    end
266                end
267            end
268        end
269        -- todo: ranges so the interface will change
270        sort(result,compare)
271        local first, last, firsti, lasti, firstr, lastr
272        local collected, nofcollected = { }, 0
273        for i=1,nofresult do
274            local r = result[i]
275            local current = r[3]
276            if not first then
277                first, last, firsti, lasti, firstr, lastr = current, current, i, i, r, r
278            elseif current == last + 1 then
279                last, lasti, lastr = current, i, r
280            else
281                if last > first + 1 then
282                    nofcollected = nofcollected + 1
283                    collected[nofcollected] = { firstr[1], firstr[2], lastr[1], lastr[2] }
284                else
285                    nofcollected = nofcollected + 1
286                    collected[nofcollected] = { firstr[1], firstr[2] }
287                    if last > first then
288                        nofcollected = nofcollected + 1
289                        collected[nofcollected] = { lastr[1], lastr[2] }
290                    end
291                end
292                first, last, firsti, lasti, firstr, lastr = current, current, i, i, r, r
293            end
294        end
295        if first and last then
296            if last > first + 1 then
297                nofcollected = nofcollected + 1
298                collected[nofcollected] = { firstr[1], firstr[2], lastr[1], lastr[2] }
299            else
300                nofcollected = nofcollected + 1
301                collected[nofcollected] = { firstr[1], firstr[2] }
302                if last > first then
303                    nofcollected = nofcollected + 1
304                    collected[nofcollected] = { lastr[1], lastr[2] }
305                end
306            end
307        end
308        if nofcollected > 0 then
309            for i=1,nofcollected do
310                local c = collected[i]
311                if c[3] then
312                    context.dowithbibtexnumrefrange(#collected,i,prefix,c[1],c[2],c[3],c[4])
313                else
314-- print(#collected,i,prefix,c[1],c[2])
315                    context.dowithbibtexnumref(#collected,i,prefix,c[1],c[2])
316                end
317            end
318        else
319            context.nobibtexnumref("error 1")
320        end
321    else
322        context.nobibtexnumref("error 2")
323    end
324end
325