m-database.lua /size: 4870 b    last modification: 2020-07-01 14:35
1if not modules then modules = { } end modules ['m-database'] = {
2    version   = 1.001,
3    comment   = "companion to m-database.mkiv",
4    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5    copyright = "PRAGMA ADE / ConTeXt Development Team",
6    license   = "see context related readme files"
7}
8
9local sub, gmatch = string.sub, string.gmatch
10local concat = table.concat
11local lpegpatterns, lpegmatch, lpegsplitat = lpeg.patterns, lpeg.match, lpeg.splitat
12local lpegP, lpegC, lpegS, lpegCt, lpegCc, lpegCs = lpeg.P, lpeg.C, lpeg.S, lpeg.Ct, lpeg.Cc, lpeg.Cs
13local stripstring = string.strip
14
15moduledata.database     = moduledata.database     or { }
16moduledata.database.csv = moduledata.database.csv or { }
17
18-- One also needs to enable context.trace, here we only plug in some code (maybe
19-- some day this tracker will also toggle the main context tracer.
20
21local trace_flush     = false  trackers.register("module.database.flush", function(v) trace_flush = v end)
22local report_database = logs.reporter("database")
23
24local context = context
25
26local l_tab   = lpegpatterns.tab
27local l_space = lpegpatterns.space
28local l_comma = lpegpatterns.comma
29local l_empty = lpegS("\t\n\r ")^0 * lpegP(-1)
30
31local v_yes   = interfaces.variables.yes
32
33local separators = { -- not interfaced
34    tab    = l_tab,
35    tabs   = l_tab^1,
36    comma  = l_comma,
37    space  = l_space,
38    spaces = l_space^1,
39}
40
41function moduledata.database.csv.process(settings)
42    local data
43    if settings.type == "file" then
44        local filename = resolvers.finders.byscheme("any",settings.database)
45        data = filename ~= "" and io.loaddata(filename)
46        data = data and string.splitlines(data)
47    else
48        data = buffers.getlines(settings.database)
49    end
50    if data and #data > 0 then
51        local catcodes = tonumber(settings.catcodes) or tex.catcodetable
52        context.pushcatcodes(catcodes)
53        if trace_flush then
54            context.pushlogger(report_database)
55        end
56        local separatorchar, quotechar, commentchar = settings.separator, settings.quotechar, settings.commentchar
57        local before, after = settings.before or "", settings.after or ""
58        local first, last = settings.first or "", settings.last or ""
59        local left, right = settings.left or "", settings.right or ""
60        local setups = settings.setups or ""
61        local strip = settings.strip == v_yes or false
62        local command = settings.command or ""
63        separatorchar = (not separatorchar and ",") or separators[separatorchar] or separatorchar
64        local separator = type(separatorchar) == "string" and lpegS(separatorchar) or separatorchar
65        local whatever  = lpegC((1 - separator)^0)
66        if quotechar and quotechar ~= "" then
67            local quotedata = nil
68            for chr in gmatch(quotechar,".") do
69                local quotechar = lpegP(chr)
70                local quoteword = lpegCs(((l_space^0 * quotechar)/"") * (1 - quotechar)^0 * ((quotechar * l_space^0)/""))
71                if quotedata then
72                    quotedata = quotedata + quoteword
73                else
74                    quotedata = quoteword
75                end
76            end
77            whatever = quotedata + whatever
78        end
79        local checker = commentchar ~= "" and lpegS(commentchar)
80        if strip then
81            whatever = whatever / stripstring
82        end
83        if left ~= "" then
84            whatever = lpegCc(left) * whatever
85        end
86        if right ~= "" then
87            whatever = whatever * lpegCc(right)
88        end
89        if command ~= "" then
90            whatever = lpegCc("{") * whatever * lpegCc("}")
91        end
92        whatever = whatever * (separator/"" * whatever)^0
93        if first ~= "" then
94            whatever = lpegCc(first) * whatever
95        end
96        if last ~= "" then
97            whatever = whatever * lpegCc(last)
98        end
99        if command ~= "" then
100            whatever = lpegCs(lpegCc(command) * whatever)
101        else
102            whatever = lpegCs(whatever)
103        end
104        local found = false
105        for i=1,#data do
106            local line = data[i]
107            if not lpegmatch(l_empty,line) and (not checker or not lpegmatch(checker,line)) then
108                if not found then
109                    if setups ~= "" then
110                        context.begingroup()
111                        context.setups { setups }
112                    end
113                    context(before)
114                    found = true
115                end
116                context(lpegmatch(whatever,line))
117            end
118        end
119        if found then
120            context(after)
121            if setups ~= "" then
122                context.endgroup()
123            end
124        end
125        context.popcatcodes()
126        if trace_flush then
127            context.poplogger()
128        end
129    else
130        -- message
131    end
132end
133