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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
local datfile = {}
local db, sql = require("data/database")()
function datfile.open(file, vertag, fixupcb)
if not db then
return nil
end
local function read(tag1, tag2, set)
local data
local stmt = db:prepare("SELECT f.data FROM \"" .. file .. "_idx\" AS fi, \"" .. file .. [["
AS f WHERE fi.type = ? AND fi.val = ? AND fi.romset = ? AND f.rowid = fi.data]])
stmt:bind_values(tag1, tag2, set)
if stmt:step() == sql.ROW then
data = stmt:get_value(0)
end
stmt:finalize()
return data
end
local ver, dbver
local filepath
local fh
for path in mame_manager:ui():options().entries.historypath:value():gmatch("([^;]+)") do
filepath = lfs.env_replace(path) .. "/" .. file
fh = io.open(filepath, "r")
if fh then
break
end
end
-- remove unsafe chars from file for use in sql statement
file = file:gsub("[^%w%._]", "")
local stmt = db:prepare("SELECT version FROM version WHERE datfile = ?")
stmt:bind_values(file)
if stmt:step() == sql.ROW then
dbver = stmt:get_value(0)
end
stmt:finalize()
if not fh and dbver then
-- data in database but missing file, just use what we have
return read, dbver
elseif not fh then
return nil
elseif not dbver then
db:exec("CREATE TABLE \"" .. file .. [[_idx" (
type VARCHAR NOT NULL,
val VARCHAR NOT NULL,
romset VARCHAR NOT NULL,
data INTEGER NOT NULL)]])
db:exec("CREATE TABLE \"" .. file .. "\" (data CLOB NOT NULL)")
db:exec("CREATE INDEX \"typeval_" .. file .. "\" ON \"" .. file .. "_idx\"(type, val)")
end
if vertag then
for line in fh:lines() do
local match = line:match(vertag .. "%s*([^%s]+)")
if match then
ver = match
break
end
end
else
-- use file ctime for version
ver = tostring(lfs.attributes(filepath, "change"))
end
if ver == dbver then
fh:close()
return read, dbver
end
if dbver then
db:exec("DELETE FROM \"" .. file .. "\"")
db:exec("DELETE FROM \"" .. file .. "_idx\"")
stmt = db:prepare("UPDATE version SET version = ? WHERE datfile = ?")
else
stmt = db:prepare("INSERT INTO version VALUES (?, ?)")
end
stmt:bind_values(ver, file)
stmt:step()
stmt:finalize()
do
local inblock = false
fh:seek("set")
local buffer = fh:read("a")
db:exec("BEGIN TRANSACTION")
local function gmatchpos()
local pos = 1
local function iter()
local tag1, tag2, data, start, inblock = false
while not data do
local spos, epos, match = buffer:find("\n($[^\n]*)", pos)
if not spos then
return nil
end
if match ~= "$end" and not inblock then
if not tag1 then
tag1 = match
else
tag2 = match
start = epos + 1
inblock = true
end
elseif inblock == true then
data = buffer:sub(start, spos)
inblock = false
end
pos = epos
end
return tag1, tag2, data
end
return iter
end
for info1, info2, data in gmatchpos() do
local tag, set = info1:match("^%$([^%s=]+)=?([^%s]*)")
if set and set ~= "" then
local tags = {}
local sets = {}
tag:gsub("([^,]+)", function(s) tags[#tags + 1] = s end)
set:gsub("([^,]+)", function(s) sets[#sets + 1] = s end)
if #tags > 0 and #sets > 0 then
local tag1 = info2:match("^$([^%s]*)")
data = data:gsub("\r", "") -- strip crs
if fixupcb then
data = fixupcb(data)
end
stmt = db:prepare("INSERT INTO \"" .. file .. "\" VALUES (?)")
stmt:bind_values(data)
stmt:step()
local row = stmt:last_insert_rowid()
stmt:finalize()
for num1, tag2 in pairs(tags) do
for num2, set in pairs(sets) do
if fixupcb then
fixupcb(data)
end
stmt = db:prepare("INSERT INTO \"" .. file .. "_idx\" VALUES (?, ?, ?, ?)")
stmt:bind_values(tag1, tag2, set, row)
stmt:step()
stmt:finalize()
end
end
end
end
end
db:exec("END TRANSACTION")
end
fh:close()
return read, ver
end
return datfile
|