summaryrefslogtreecommitdiffstats
path: root/player/lua/options.lua
blob: 3a05c08ea846d78e09906962b1f3c4851900acd7 (plain)
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
local msg = require 'mp.msg'

local function val2str(val)
    if type(val) == "boolean" then
        if val then val = "yes" else val = "no" end
    end
    return val
end

-- converts val to type of desttypeval
local function typeconv(desttypeval, val)
    if type(desttypeval) == "boolean" then
        if val == "yes" then
            val = true
        elseif val == "no" then
            val = false
        else
            msg.error("Error: Can't convert " .. val .. " to boolean!")
            val = nil
        end
    elseif type(desttypeval) == "number" then
        if not (tonumber(val) == nil) then
            val = tonumber(val)
        else
            msg.error("Error: Can't convert " .. val .. " to number!")
            val = nil
        end
    end
    return val
end

-- performs a deep-copy of the given option value
local function opt_copy(val)
    return val -- no tables currently
end

-- compares the given option values for equality
local function opt_equal(val1, val2)
    return val1 == val2
end

local function read_options(options, identifier, on_update)
    if identifier == nil then
        identifier = mp.get_script_name()
    end
    msg.debug("reading options for " .. identifier)

    -- read config file
    local conffilename = "script-opts/" .. identifier .. ".conf"
    local conffile = mp.find_config_file(conffilename)
    if conffile == nil then
        msg.debug(conffilename .. " not found.")
        conffilename = "lua-settings/" .. identifier .. ".conf"
        conffile = mp.find_config_file(conffilename)
        if conffile then
            msg.warn("lua-settings/ is deprecated, use directory script-opts/")
        end
    end
    local f = conffile and io.open(conffile,"r")
    if f == nil then
        -- config not found
        msg.debug(conffilename .. " not found.")
    else
        -- config exists, read values
        msg.verbose("Opened config file " .. conffilename .. ".")
        local linecounter = 1
        for line in f:lines() do
            if string.find(line, "#") == 1 then

            else
                local eqpos = string.find(line, "=")
                if eqpos == nil then

                else
                    local key = string.sub(line, 1, eqpos-1)
                    local val = string.sub(line, eqpos+1)

                    -- match found values with defaults
                    if options[key] == nil then
                        msg.warn(conffilename..":"..linecounter..
                            " unknown key " .. key .. ", ignoring")
                    else
                        local convval = typeconv(options[key], val)
                        if convval == nil then
                            msg.error(conffilename..":"..linecounter..
                                " error converting value '" .. val ..
                                "' for key '" .. key .. "'")
                        else
                            options[key] = convval
                        end
                    end
                end
            end
            linecounter = linecounter + 1
        end
        io.close(f)
    end

    --parse command-line options
    local prefix = identifier.."-"

    local option_types = {}
    for key, value in pairs(options) do
        option_types[key] = opt_copy(value)
    end

    local function parse_opts(full, options)
        local changelist = {}
        for key, val in pairs(full) do
            if not (string.find(key, prefix, 1, true) == nil) then
                key = string.sub(key, string.len(prefix)+1)

                -- match found values with defaults
                if option_types[key] == nil then
                    msg.warn("script-opts: unknown key " .. key .. ", ignoring")
                else
                    local convval = typeconv(option_types[key], val)
                    if convval == nil then
                        msg.error("script-opts: error converting value '" .. val ..
                            "' for key '" .. key .. "'")
                    else
                        if not opt_equal(options[key], convval) then
                            changelist[key] = true
                            options[key] = convval
                        end
                    end
                end
            end
        end
        return changelist
    end

    --initial
    parse_opts(mp.get_property_native("options/script-opts"), options)

    --runtime updates
    if on_update then
        -- Current option state, so that we can detect changes, even if the
        -- caller messes with the options table.
        local cur_opts = {}

        for key, value in pairs(options) do
            cur_opts[key] = opt_copy(value)
        end

        mp.observe_property("options/script-opts", "native", function(name, val)
            local changelist = parse_opts(val, cur_opts)
            for key, _ in pairs(changelist) do
                -- copy to user
                options[key] = opt_copy(cur_opts[key])
            end
            if #changelist then
                on_update(changelist)
            end
        end)
    end

end

-- backwards compatibility with broken read_options export
_G.read_options = read_options

return {
    read_options = read_options,
}