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
156
157
158
159
|
local sql = require('lsqlite3')
local db
local function check_db_result(msg)
if db:errcode() > sql.OK then
emu.print_error(string.format('Error: %s (%s - %s)', msg, db:errcode(), db:errmsg()))
return false
end
return true
end
local function settings_path()
return manager.machine.options.entries.homepath:value():match('([^;]+)') .. '/data'
end
local function check_version_table()
local found = false
db:exec(
[[SELECT COUNT(*) FROM sqlite_master WHERE name = 'version' AND type = 'table';]],
function (udata, cols, values, names)
found = tonumber(values[1]) > 0
return 0
end)
if check_db_result('checking for "version" table') and (not found) then
db:exec(
[[CREATE TABLE version (
datfile VARCHAR NOT NULL,
version VARCHAR NOT NULL,
PRIMARY KEY (datfile));]])
found = check_db_result('creating "version" table')
end
if not found then
db:close()
db = nil
end
end
local function open_existing()
db = sql.open(settings_path() .. '/history.db', sql.OPEN_READWRITE)
if db then
check_version_table()
end
return db
end
local function open_create()
-- first try to create settings directory
local dir = settings_path()
local attr = lfs.attributes(dir)
if (not attr) and (not lfs.mkdir(dir)) then
emu.print_error(string.format('Error creating data plugin settings directory "%s"', dir))
elseif attr and (attr.mode ~= 'directory') then
emu.print_error(string.format('Error opening data plugin database: "%s" is not a directory', dir))
else
-- now try to open the database
local dbpath = dir .. '/history.db'
db = sql.open(dbpath, sql.OPEN_READWRITE | sql.OPEN_CREATE)
if not db then
emu.print_error(string.format('Error opening data plugin database "%s"', dbpath))
else
check_version_table()
end
end
return db
end
local dbtable = {
ROW = sql.ROW,
BUSY = sql.BUSY,
DONE = sql.DONE,
check = check_db_result }
function dbtable.sanitize_name(name)
return name:gsub('[^%w%."]', '_')
end
function dbtable.get_version(filename)
-- don't try to create the database here, just return nil if it doesn't exist
if (not db) and (not open_existing()) then
return nil
end
local query = db:prepare([[SELECT version FROM version WHERE datfile = ?;]])
query:bind_values(filename)
local result
while result == nil do
local status = query:step()
if status == sql.ROW then
result = query:get_value(0)
elseif status ~= sql.BUSY then
break
end
end
query:finalize()
return result
end
function dbtable.set_version(filename, version)
if (not db) and (not open_create()) then
return nil
end
local query
if version ~= nil then
query = db:prepare(
[[INSERT INTO version (datfile, version) VALUES (?1, ?2)
ON CONFLICT(datfile) DO UPDATE set version = ?2;]])
query:bind_values(filename, version)
else
query = db:prepare([[DELETE FROM version WHERE datfile = ?1;]])
query:bind_values(filename)
end
local result
while result == nil do
local status = query:step()
if status == sql.DONE then
result = true
elseif result ~= sql.ROW then
result = false
end
end
query:finalize()
return result
end
function dbtable.prepare(...)
if (not db) and open_create() then
dbtable.prepare = function (...) return db:prepare(...) end
end
if db then
return db:prepare(...)
else
return nil
end
end
function dbtable.exec(...)
if (not db) and open_create() then
dbtable.exec = function (...) return db:exec(...) end
end
if db then
return db:exec(...)
else
return nil
end
end
function dbtable.open_data_file(file)
local fh, filepath
for path in mame_manager.ui.options.entries.historypath:value():gmatch('([^;]+)') do
filepath = path .. '/' .. file
fh = io.open(filepath, 'r')
if fh then
break
end
end
return fh, filepath, dbtable.sanitize_name(file), dbtable.get_version(file)
end
return dbtable
|