summaryrefslogtreecommitdiff
path: root/tex/context/base/m-database.lua
blob: b9ec3aa3691aa10825fe1e38eeb8f66ae59231a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
if not modules then modules = { } end modules ['m-database'] = {
    version   = 1.001,
    comment   = "companion to m-database.mkiv",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

local sub, gmatch, format = string.sub, string.gmatch, string.format
local concat = table.concat
local lpegpatterns, lpegmatch, lpegsplitat = lpeg.patterns, lpeg.match, lpeg.splitat
local lpegP, lpegC, lpegS, lpegCt = lpeg.P, lpeg.C, lpeg.S, lpeg.Ct

-- One also needs to enable context.trace, here we only plug in some code (maybe
-- some day this tracker will also toggle the main context tracer.

local trace_flush = false  trackers.register("module.database.flush", function(v) trace_flush = v end)

local report_database = logs.reporter("database")

buffers.database = buffers.database or { }

local separators = { -- not interfaced
    tab    = lpegpatterns.tab,
    tabs   = lpegpatterns.tab^1,
    comma  = lpegpatterns.comma,
    space  = lpegpatterns.space,
    spaces = lpegpatterns.space^1,
}

function buffers.database.process(settings)
    local data
    if settings.type == "file" then
        local filename = resolvers.finders.byscheme("any",settings.database)
        data = filename ~= "" and io.loaddata(filename)
        data = data and string.splitlines(data)
    else
        data = buffers.getlines(settings.database)
    end
    if data and #data > 0 then
        if trace_flush then
            context.pushlogger(report_database)
        end
        local separatorchar, quotechar, commentchar = settings.separator, settings.quotechar, settings.commentchar
        local before, after = settings.before or "", settings.after or ""
        local first, last = settings.first or "", settings.last or ""
        local left, right = settings.left or "", settings.right or ""
        local setups = settings.setups or ""
        local command = settings.command
        separatorchar = (not separatorchar and ",") or separators[separatorchar] or separatorchar
        local separator = type(separatorchar) == "string" and lpegS(separatorchar) or separatorchar
        local whatever  = lpegC((1 - separator)^0)
        if quotechar and quotechar ~= "" then
            local quotedata = nil
            for chr in gmatch(quotechar,".") do
                local quotechar = lpegP(chr)
                local quoteword = quotechar * lpeg.C((1 - quotechar)^0) * quotechar
                if quotedata then
                    quotedata = quotedata + quoteword
                else
                    quotedata = quoteword
                end
            end
            whatever = quotedata + whatever
        end
        local checker = commentchar ~= "" and lpeg.S(commentchar)
        local splitter = lpegCt(whatever * (separator * whatever)^0)
        local found = false
        for i=1,#data do
            local line = data[i]
            if line ~= "" and (not checker or not lpegmatch(checker,line)) then
                local list = lpegmatch(splitter,line)
                if not found then
                    if setups ~= "" then
                        context.begingroup()
                        context.setups { setups }
                    end
                    context(before)
                    found = true
                end
                if trace_flush then
                    local result, r = { }, 0
                    r = r + 1 ; result[r] = first
                    for j=1,#list do
                        r = r + 1 ; result[r] = left
                        if command == "" then
                            r = r + 1 ; result[r] = list[j]
                        else
                            r = r + 1 ; result[r] = command
                            r = r + 1 ; result[r] = "{"
                            r = r + 1 ; result[r] = list[j]
                            r = r + 1 ; result[r] = "}"
                        end
                        r = r + 1 ; result[r] = right
                    end
                    r = r + 1 ; result[r] = last
                    context(concat(result))
                else
                    context(first)
                    for j=1,#list do
                        context(left)
                        if command == "" then
                            context(list[j])
                        else
                            context(command)
                            context(false,list[j])
                        end
                        context(right)
                    end
                    context(last)
                end
            end
        end
        if found then
            context(after)
            if setups ~= "" then
                context.endgroup()
            end
        end
        if trace_flush then
            context.poplogger()
        end
    else
        -- message
    end
end