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
19
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 = {
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
131 end
132end
133 |