summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/bibl-bib.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/bibl-bib.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/bibl-bib.lua233
1 files changed, 233 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/bibl-bib.lua b/Master/texmf-dist/tex/context/base/bibl-bib.lua
new file mode 100644
index 00000000000..028202ec22f
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/bibl-bib.lua
@@ -0,0 +1,233 @@
+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"
+}
+
+--[[ldx--
+<p>This is a prelude to integrated bibliography support. This file just loads
+bibtex files and converts them to xml so that the we access the content
+in a convenient way. Actually handling the data takes place elsewhere.</p>
+--ldx]]--
+
+local lower, format = string.lower, string.format
+local next = next
+
+bibtex = bibtex or { }
+
+bibtex.size = 0
+bibtex.definitions = 0
+bibtex.shortcuts = 0
+
+local shortcuts = { }
+local data = { }
+local entries
+
+local function do_shortcut(tag,key,value)
+ bibtex.shortcuts = bibtex.shortcuts + 1
+ if lower(tag) == "@string" then
+ shortcuts[key] = value
+ end
+end
+
+local function do_definition(tag,key,tab) -- maybe check entries here (saves memory)
+ if not entries or entries[key] then
+ bibtex.definitions = bibtex.definitions + 1
+ local t = { }
+ for i=1,#tab,2 do
+ t[tab[i]] = tab[i+1]
+ end
+ local p = data[tag]
+ if not p then
+ data[tag] = { [key] = t }
+ else
+ p[key] = t
+ end
+ end
+end
+
+local function resolve(s)
+ return shortcuts[s] or ""
+end
+
+local percent = lpeg.P("%")
+local start = lpeg.P("@")
+local comma = lpeg.P(",")
+local hash = lpeg.P("#")
+local escape = lpeg.P("\\")
+local single = lpeg.P("'")
+local double = lpeg.P('"')
+local left = lpeg.P('{')
+local right = lpeg.P('}')
+local both = left + right
+local lineending = lpeg.S("\n\r")
+local space = lpeg.S(" \t\n\r\f")
+local spacing = space^0
+local equal = lpeg.P("=")
+local collapsed = (space^1)/ " "
+
+local function add(a,b) if b then return a..b else return a end end
+
+local keyword = lpeg.C((lpeg.R("az","AZ","09") + lpeg.S("@_:-"))^1) -- lpeg.C((1-space)^1)
+local s_quoted = ((escape*single) + collapsed + (1-single))^0
+local d_quoted = ((escape*double) + collapsed + (1-double))^0
+local balanced = lpeg.P {
+ [1] = ((escape * (left+right)) + (1 - (left+right)) + lpeg.V(2))^0,
+ [2] = left * lpeg.V(1) * right
+}
+
+local s_value = (single/"") * s_quoted * (single/"")
+local d_value = (double/"") * d_quoted * (double/"")
+local b_value = (left /"") * balanced * (right /"")
+local r_value = keyword/resolve
+
+local somevalue = s_value + d_value + b_value + r_value
+local value = lpeg.Cs((somevalue * ((spacing * hash * spacing)/"" * somevalue)^0))
+
+local assignment = spacing * keyword * spacing * equal * spacing * value * spacing
+local shortcut = keyword * spacing * left * spacing * (assignment * comma^0)^0 * spacing * right
+local definition = keyword * spacing * left * spacing * keyword * comma * lpeg.Ct((assignment * comma^0)^0) * spacing * right
+local comment = keyword * spacing * left * (1-right)^0 * spacing * right
+local forget = percent^1 * (1-lineending)^0
+
+-- todo \%
+
+local grammar = (space + forget + shortcut/do_shortcut + definition/do_definition + comment + 1)^0
+
+function bibtex.convert(session,content)
+ statistics.starttiming(bibtex)
+ data, shortcuts, entries = session.data, session.shortcuts, session.entries
+ -- session.size = session.size + #content
+ bibtex.size = bibtex.size + #content
+ grammar:match(content or "")
+ statistics.stoptiming(bibtex)
+end
+
+function bibtex.load(session,filename)
+ local filename = resolvers.find_file(filename,"bib")
+ if filename ~= "" then
+ bibtex.convert(session,io.loaddata(filename) or "")
+ end
+end
+
+function bibtex.new()
+ return {
+ data = { },
+ shortcuts = { },
+ xml = xml.convert("<?xml version='1.0' standalone='yes'?>\n<bibtex></bibtex>"),
+ size = 0,
+ entries = nil,
+ }
+end
+
+local escaped_pattern = xml.escaped_pattern
+
+function bibtex.toxml(session)
+ -- we can always speed this up if needed
+ -- format slows down things a bit but who cares
+ statistics.starttiming(bibtex)
+ local result = { }
+ local entries = session.entries
+ result[#result+1] = format("<?xml version='1.0' standalone='yes'?>")
+ result[#result+1] = format("<bibtex>")
+ for id, categories in next, session.data do
+ result[#result+1] = format(" <c n='%s'>",id)
+ for name, entry in next, categories do
+ if not entries or entries[name] then
+ result[#result+1] = format(" <e n='%s'>",name)
+ for key, value in next, entry do
+ value = escaped_pattern:match(value)
+ if value ~= "" then
+ result[#result+1] = format(" <v n='%s'>%s</v>",key,value)
+ end
+ end
+ result[#result+1] = format(" </e>")
+ end
+ end
+ result[#result+1] = format(" </c>")
+ end
+ result[#result+1] = format("</bibtex>")
+ session.xml = xml.convert(table.concat(result,"\n"))
+ statistics.stoptiming(bibtex)
+end
+
+statistics.register("bibtex load time", function()
+ local size = bibtex.size
+ if size > 0 then
+ return format("%s seconds (%s bytes, %s definitions, %s shortcuts)",
+ statistics.elapsedtime(bibtex),size,bibtex.definitions,bibtex.shortcuts)
+ else
+ return nil
+ end
+end)
+
+--~ str = [[
+--~ @COMMENT { CRAP }
+--~ @STRING{ hans = "h a n s" }
+--~ @STRING{ taco = "t a c o" }
+--~ @SOMETHING{ key1, abc = "t a c o" , def = "h a n s" }
+--~ @SOMETHING{ key2, abc = hans # taco }
+--~ @SOMETHING{ key3, abc = "hans" # taco }
+--~ @SOMETHING{ key4, abc = hans # "taco" }
+--~ @SOMETHING{ key5, abc = hans # taco # "hans" # "taco"}
+--~ @SOMETHING{ key6, abc = {oeps {oeps} oeps} }
+--~ ]]
+
+--~ local session = bibtex.new()
+--~ bibtex.convert(session,str)
+--~ bibtex.toxml(session)
+--~ print(session.size,statistics.elapsedtime(bibtex))
+
+--~ local session = bibtex.new()
+--~ bibtex.load(session,"IEEEabrv.bib")
+--~ bibtex.load(session,"IEEEfull.bib")
+--~ bibtex.load(session,"IEEEexample.bib")
+--~ bibtex.toxml(session)
+--~ print(session.size,statistics.elapsedtime(bibtex))
+
+--~ local session = bibtex.new()
+--~ bibtex.load(session,"gut.bib")
+--~ bibtex.load(session,"komoedie.bib")
+--~ bibtex.load(session,"texbook1.bib")
+--~ bibtex.load(session,"texbook2.bib")
+--~ bibtex.load(session,"texbook3.bib")
+--~ bibtex.load(session,"texgraph.bib")
+--~ bibtex.load(session,"texjourn.bib")
+--~ bibtex.load(session,"texnique.bib")
+--~ bibtex.load(session,"tugboat.bib")
+--~ bibtex.toxml(session)
+--~ print(session.size,statistics.elapsedtime(bibtex))
+
+--~ print(table.serialize(session.data))
+--~ print(table.serialize(session.shortcuts))
+--~ print(xml.serialize(session.xml))
+
+-- this will move:
+
+if commands then
+
+ local sessions = { }
+
+ function commands.definebibtexsession(name)
+ sessions[name] = bibtex.new()
+ end
+ function commands.preparebibtexsession(name)
+ bibtex.toxml(sessions[name])
+ lxml.register("bibtex:"..name,sessions[name].xml)
+ end
+ function commands.registerbibtexfile(name,filename)
+ bibtex.load(sessions[name],filename)
+ end
+ function commands.registerbibtexentry(name,entry)
+ local session = sessions[name]
+ local entries = session.entries
+ if not entries then
+ session.entries = { [entry] = true }
+ else
+ entries[entry] = true
+ end
+ end
+
+end