summaryrefslogtreecommitdiffstatshomepage
path: root/plugins/portname/init.lua
blob: e231931a34740c3fb7d52eb3ed8b5991c2de715c (plain) (blame)
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
-- license:BSD-3-Clause
-- copyright-holders:Carl
-- data files are json files named <romname>.json
-- {
--   "ports":{
--     "<ioport name>":{
--       "labels":{
--         "<field mask>":{
--           "player":<int player number>,
--           "name":"<field label>"
--         }
--     },{
--       ...
--     }
--   }
-- }
-- any additional metadata can be included for other usage
-- and will be ignored
local exports = {}
exports.name = "portname"
exports.version = "0.0.1"
exports.description = "IOPort name/translation plugin"
exports.license = "The BSD 3-Clause License"
exports.author = { name = "Carl" }

local portname = exports

function portname.startplugin()
	local json = require("json")
	local ctrlrpath = lfs.env_replace(manager:options().entries.ctrlrpath:value():match("([^;]+)"))
	local function get_filename(nosoft)
		local filename
		if emu.softname() ~= "" and not nosoft then
			local soft = emu.softname():match("([^:]*)$")
			filename = emu.romname() .. "_" .. soft .. ".json"
		else
			filename = emu.romname() .. ".json"
		end
		return filename
	end

	emu.register_start(function()
		local file = emu.file(ctrlrpath .. "/portname", "r")
		local ret = file:open(get_filename())
		if ret then
			ret = file:open(get_filename(true))
			if ret then
				ret = file:open(manager:machine():system().parent .. ".json")
				if ret then
					return
				end
			end
		end
		local ctable = json.parse(file:read(file:size()))
		for pname, port in pairs(ctable.ports) do
			local ioport = manager:machine():ioport().ports[pname]
			if ioport then
				for mask, label in pairs(port.labels) do
					for num3, field in pairs(ioport.fields) do
						local nummask = tonumber(mask, 16)
						if nummask == field.mask and label.player == field.player then
							field.live.name = label.name
						end
					end
				end
			end
		end
	end)

	local function menu_populate()
		return {{ _("Save input names to file"), "", 0 }}
	end

	local function menu_callback(index, event)
		if event == "select" then
			local ports = {}
			for pname, port in pairs(manager:machine():ioport().ports) do
				local labels = {}
				local sort = {}
				for fname, field in pairs(port.fields) do
					local mask = string.format("%x", field.mask)
					if not labels[mask] then
						sort[#sort + 1] = mask
						labels[mask] = { name = fname, player = field.player }
						setmetatable(labels[mask], { __tojson = function(v,s)
							local label = { name = v.name, player = v.player }
							setmetatable(label, { __jsonorder = { "player", "name" }})
							return json.stringify(label) end })
					end
				end
				if #sort > 0 then
					table.sort(sort, function(i, j) return tonumber(i, 16) < tonumber(j, 16) end)
					setmetatable(labels, { __jsonorder = sort })
					ports[pname] = { labels = labels }
				end
			end
			local function check_path(path)
				local attr = lfs.attributes(path)
				if not attr then
					lfs.mkdir(path)
					if not lfs.attributes(path) then
						manager:machine():popmessage(_("Failed to save input name file"))
						emu.print_verbose("portname: unable to create path " .. path .. "\n")
						return false
				end
				elseif attr.mode ~= "directory" then
					manager:machine():popmessage(_("Failed to save input name file"))
					emu.print_verbose("portname: path exists but isn't directory " .. path .. "\n")
					return false
				end
				return true
			end
			if not check_path(ctrlrpath) then
				return false
			end
			if not check_path(ctrlrpath .. "/portname") then
				return false
			end
			local filename = get_filename()
			local file = io.open(ctrlrpath .. "/portname/" .. filename, "r")
			if file then
				emu.print_verbose("portname: input name file exists " .. filename .. "\n")
				manager:machine():popmessage(_("Failed to save input name file"))
				file:close()
				return false
			end
			file = io.open(ctrlrpath .. "/portname/" .. filename, "w")
			local ctable = { romname = emu.romname(), ports = ports }
			if emu.softname() ~= "" then
				ctable.softname = emu.softname()
			end
			setmetatable(ctable, { __jsonorder = { "romname", "softname", "ports" }})
			file:write(json.stringify(ctable, { indent = true }))
			file:close()
			manager:machine():popmessage(string.format(_("Input port name file saved to %s"), ctrlrpath .. "/portname/" .. filename))
		end
		return false
	end

	emu.register_menu(menu_callback, menu_populate, _("Input ports"))
end

return exports