summaryrefslogtreecommitdiffstatshomepage
path: root/plugins/portname/init.lua
blob: 3c04d26f72ad3e73c50688b35f7a0ed9d8b1705f (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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
-- license:BSD-3-Clause
-- copyright-holders:Carl
-- data files are json files named <romname>.json
-- {
--   "import":"<import filename>"
--   "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

	local function parse_names(ctable, depth)
		if depth >= 5 then
			emu.print_error("portname: max import depth exceeded\n")
			return
		end
		if ctable.import then
			local file = emu.file(ctrlrpath .. "/portname", "r")
			local ret = file:open(ctable.import)
			if not ret then
				parse_names(json.parse(file:read(file:size())), depth + 1)
			end
		end
		if not ctable.ports then
			return
		end
		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

	emu.register_start(function()
		local file = emu.file(ctrlrpath .. "/portname", "r")
		local ret = file:open(get_filename())
		if ret then
			if emu.softname() ~= "" then
				local parent
				for tag, image in pairs(manager:machine().images) do
					parent = image.software_parent
					if parent ~= "" then
						break
					end
				end
				if parent ~= "" then
					ret = file:open(emu.romname() .. "_" .. parent:match("([^:]*)$")  .. ".json")
				end
			end
			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
		end
		parse_names(json.parse(file:read(file:size())), 0)
	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