bibl-tra.lua / last modification: 2010-02-12 23:30
if not modules then modules = { } end modules ['bibl-bib'] = {
    version   = 1.001,
    comment   = "this module is the basis for the lxml-* ones",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

bibtex       = bibtex       or { }
bibtex.hacks = bibtex.hacks or { }

local match, gmatch, format, concat, sort = string.match, string.gmatch, string.format, table.concat, table.sort
local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes
local variables, constants = interfaces.variables, interfaces.constants

local trace_bibtex = false  trackers.register("publications.bibtex", function(v) trace_bibtex = v end)

local hacks = bibtex.hacks

local list, done, alldone, used, registered, ordered  = { }, { }, { }, { }, { }, { }
local mode = 0

local template = string.striplong([[
  \citation{*}
  \bibstyle{cont-%s}
  \bibdata{%s}
]])

function hacks.process(settings)
    local style = settings.style or ""
    local database = settings.database or ""
    local jobname = tex.jobname
    if database ~= "" then
        interfaces.showmessage("publications",3)
        io.savedata(file.addsuffix(jobname,"aux"),format(template,style,database))
        if trace_bibtex then
            logs.report("publications","processing bibtex file '%s'",jobname)
        end
        os.execute(format("bibtex %s",jobname))
        -- purge 'm
    end
end

function hacks.register(str)
    if trace_bibtex then
        logs.report("publications","registering bibtex entry '%s'",str)
    end
    registered[#registered+1] = str
    ordered[str] = #registered
end

function hacks.reset(m)
    mode, list, done = m, { }, { }
end

function hacks.add(str,listindex)
    if not str or mode == 0 then
        -- skip
    elseif mode == 1 then
        -- all locals but no duplicates
        local sc = structure.sections.currentid()
        if done[str] ~= sc then
            done[str], alldone[str] = sc, true
            list[#list+1] = { str, listindex }
        end
    elseif mode == 2 then
        -- all locals but no preceding
        local sc = structure.sections.currentid()
        if not alldone[str] and done[str] ~= sc then
            done[str], alldone[str] = sc, true
            list[#list+1] = { str, listindex }
        end
    end
end

local function compare(a,b)
    return ordered[a[1]] < ordered[b[1]]
end

local function compare(a,b)
    local aa, bb = a[1], b[1]
    if aa and bb then
        return ordered[aa] < ordered[bb]
    else
        return true
    end
end

function hacks.flush(sortvariant)
    if sortvariant == "" or sortvariant == variables.cite or sortvariant == "default" then
        -- order is cite order i.e. same as list
    else
        sort(list,compare)
    end
    for i=1,#list do
        texsprint(ctxcatcodes,format("\\doprocessbibtexentry{%s}",list[i][1]))
    end
end

function hacks.registerplaced(str)
    used[str] = true
end

function hacks.doifalreadyplaced(str)
    commands.testcase(used[str])
end

-- we ask for <n>:tag but when we can't find it we go back
-- to look for previous definitions, and when not found again
-- we look forward

local function compare(a,b)
    return a[3] < b[3]
end

function hacks.resolve(prefix,block,reference) -- maybe already feed it split
    local subset = jobreferences.collected[prefix or ""] or jobreferences.collected[""]
    if subset then
        local result, done = { }, { }
        block = tonumber(block)
        for rest in gmatch(reference,"([^,]+)") do
            local blk, tag, found = block, nil, nil
            if block then
                tag = blk .. ":" .. rest
                found = subset[tag]
                if not found then
                    for i=block-1,1,-1 do
                        tag = i .. ":" .. rest
                        found = subset[tag]
                        if found then
                            blk = i
                            break
                        end
                    end
                end
            end
            if not found then
                blk = "*"
                tag = blk .. ":" .. rest
                found = subset[tag]
            end
            if found then
                local current = found.entries and found.entries.text
                if current and not done[current] then
                    result[#result+1] = { blk, rest, current }
                    done[current] = true
                end
            end
        end
        -- todo: ranges so the interface will change
        sort(result,compare)
        local first, last, firsti, lasti, firstr, lastr
        local collected = { }
        for i=1,#result do
            local r = result[i]
            local current = r[3]
            if not first then
                first, last, firsti, lasti, firstr, lastr = current, current, i, i, r, r
            elseif current == last + 1 then
                last, lasti, lastr = current, i, r
            else
                if last > first + 1 then
                    collected[#collected+1] = { firstr[1], firstr[2], lastr[1], lastr[2] }
                else
                    collected[#collected+1] = { firstr[1], firstr[2] }
                    if last > first then
                        collected[#collected+1] = { lastr[1], lastr[2] }
                    end
                end
                first, last, firsti, lasti, firstr, lastr = current, current, i, i, r, r
            end
        end
        if first then
            if last > first + 1 then
                collected[#collected+1] = { firstr[1], firstr[2], lastr[1], lastr[2] }
            else
                collected[#collected+1] = { firstr[1], firstr[2] }
                if last > first then
                    collected[#collected+1] = { lastr[1], lastr[2] }
                end
            end
        end
        for i=1,#collected do
            local c = collected[i]
            if c[3] then
                texsprint(ctxcatcodes,format("\\dowithbibtexnumrefrange{%s}{%s}{%s}{%s}{%s}{%s}{%s}",#collected,i,prefix,c[1],c[2],c[3],c[4]))
            else
                texsprint(ctxcatcodes,format("\\dowithbibtexnumref{%s}{%s}{%s}{%s}{%s}",#collected,i,prefix,c[1],c[2]))
            end
        end
    end
end

-- we've decided that external references make no sense
--
-- local function compare(a,b)
--     return a[3] < b[3]
-- end
--
-- local function resolve(subset,block,rest)
--     local blk, tag, found = block, nil, nil
--     if rest then
--         if block then
--             tag = blk .. ":" .. rest
--             found = subset[tag]
--             if not found then
--                 for i=block-1,1,-1 do
--                     tag = i .. ":" .. rest
--                     found = subset[tag]
--                     if found then
--                         blk = i
--                         break
--                     end
--                 end
--             end
--         end
--         if not found then
--             blk = "*"
--             tag = blk .. ":" .. rest
--             found = subset[tag]
--         end
--     end
--     return blk, rest, found
-- end

-- local function set_error(results,...)
--     local re = results[false]
--     if not re then re = { } results[false] = re end
--     re[#re+1] = { format(...) }
-- end
--
-- local function resolve_outer(results,outer,inner)
--     if inner then
--         if outer then
--             local re = results[outer]
--             if not re then re = { } results[outer] = re end
--             -- todo: external refs
--             re[#re+1] = { format("%s: %s",outer,inner) }
--         else
--             set_error(results,"no outer for inner: %s",inner)
--         end
--     else
--         set_error(results,"no inner for outer: %s",outer)
--     end
-- end
--
-- function hacks.resolve(prefix,block,reference) -- maybe already feed it split
--     local set, bug = jobreferences.identify(prefix,reference)
--     local subset = jobreferences.collected[prefix or ""] or jobreferences.collected[""]
--     if subset then
--         local jobname = tex.jobname
--         local results, done = { [jobname] = { } }, { }
--         local rj = results[jobname]
--         block = tonumber(block)
--         for i=1,#set do
--             local s = set[i]
--             local inner, outer, special = s.inner, s.outer, s.special
--             if special == "file" then
--                 resolve_outer(results,outer,s.operation)
--             elseif outer then
--                 resolve_outer(results,outer,inner)
--             elseif inner then
--                 local blk, inner, found = resolve(subset,block,inner)
--                 local current = found and found.entries and found.entries.text
--                 if current and not done[current] then
--                     rj[#rj+1] = { blk, inner, current }
--                     done[current] = true
--                 end
--             end
--         end
--         for where, result in next, results do
--             if where then -- else errors
--                 sort(result,compare)
--             end
--         end
--         local first, last, firsti, lasti, firstr, lastr
--         local function finish(cw)
--             if first then
--                 if last > first + 1 then
--                     cw[#cw+1] = { firstr[1], firstr[2], lastr[1], lastr[2] }
--                 else
--                     cw[#cw+1] = { firstr[1], firstr[2] }
--                     if last > first then
--                         cw[#cw+1] = { lastr[1], lastr[2] }
--                     end
--                 end
--             end
--         end
--         local collections = { }
--         for where, result in next, results do
--             if where == jobname then
--                 local cw = { }
--                 for i=1,#result do
--                     local r = result[i]
--                     local current = r[3]
--                     if not first then
--                         first, last, firsti, lasti, firstr, lastr = current, current, i, i, r, r
--                     elseif current == last + 1 then
--                         last, lasti, lastr = current, i, r
--                     else
--                         finish(cw)
--                         first, last, firsti, lasti, firstr, lastr = current, current, i, i, r, r
--                     end
--                 end
--                 finish(cw)
--                 if next(cw) then collections[where] = cw end
--             elseif where == false then
--                 collections[where] = result -- temp hack
--             else
--                 collections[where] = result -- temp hack
--             end
--         end
--         for where, collection in next, collections do
--             local n = #collection
--             for i=1,n do
--                 local c = collection[i]
--                 if where == jobname then
--                     -- internals
--                     if c[4] then
--                         texsprint(ctxcatcodes,format("\\dowithbibtexnumrefrange{%s}{%s}{%s}{%s}{%s}{%s}{%s}",n,i,prefix,c[1],c[2],c[3],c[4]))
--                     else
--                         texsprint(ctxcatcodes,format("\\dowithbibtexnumref{%s}{%s}{%s}{%s}{%s}",n,i,prefix,c[1],c[2]))
--                     end
--                 elseif where == false then
--                     -- errors
--                     texsprint(ctxcatcodes,c[1])
--                 else
--                     -- externals
--                     texsprint(ctxcatcodes,c[1])
--                 end
--             end
--         end
--     end
-- end