+
+--- Get an option or list and return values as table.
+-- @param config UCI config
+-- @param section UCI section name
+-- @param option UCI option
+-- @return UCI value
+function Cursor.get_list(self, config, section, option)
+ if config and section and option then
+ local val = self:get(config, section, option)
+ return ( type(val) == "table" and val or { val } )
+ end
+ return nil
+end
+
+--- Set given values as list.
+-- @param config UCI config
+-- @param section UCI section name
+-- @param option UCI option
+-- @param value UCI value
+-- @return Boolean whether operation succeeded
+function Cursor.set_list(self, config, section, option, value)
+ if config and section and option then
+ return self:set(
+ config, section, option,
+ ( type(value) == "table" and value or { value } )
+ )
+ end
+ return false
+end
+
+
+Cursor._changes = Cursor.changes
+function Cursor.changes(self, config)
+ if config then
+ return Cursor._changes(self, config)
+ else
+ local changes = Cursor._changes(self)
+ util.copcall(function()
+ for k,v in pairs(require "luci.fs".dir(self:get_savedir())) do
+ if v ~= "." and v ~= ".." then
+ util.update(changes, Cursor._changes(self, v))
+ end
+ end
+ end)
+ return changes
+ end
+end
+
+
+-- Return a list of initscripts affected by configuration changes.
+function Cursor._affected(self, configlist)
+ configlist = type(configlist) == "table" and configlist or {configlist}
+
+ local c = cursor()
+ c:load("ucitrack")
+
+ -- Resolve dependencies
+ local reloadlist = {}
+
+ local function _resolve_deps(name)
+ local reload = {name}
+ local deps = {}
+
+ c:foreach("ucitrack", name,
+ function(section)
+ if section.affects then
+ for i, aff in ipairs(section.affects) do
+ deps[#deps+1] = aff
+ end
+ end
+ end)
+
+ for i, dep in ipairs(deps) do
+ for j, add in ipairs(_resolve_deps(dep)) do
+ reload[#reload+1] = add
+ end
+ end
+
+ return reload
+ end
+
+ -- Collect initscripts
+ for j, config in ipairs(configlist) do
+ for i, e in ipairs(_resolve_deps(config)) do
+ if not util.contains(reloadlist, e) then
+ reloadlist[#reloadlist+1] = e
+ end
+ end
+ end
+
+ return reloadlist
+end
+
+
+--- Add an anonymous section.
+-- @class function
+-- @name Cursor.add
+-- @param config UCI config
+-- @param type UCI section type
+-- @return Name of created section
+
+--- Get a table of unsaved changes.
+-- @class function
+-- @name Cursor.changes
+-- @param config UCI config
+-- @return Table of changes
+
+--- Commit unsaved changes.
+-- @class function
+-- @name Cursor.commit
+-- @param config UCI config
+-- @return Boolean whether operation succeeded
+-- @see Cursor.revert
+
+--- Deletes a section or an option.
+-- @class function
+-- @name Cursor.delete
+-- @param config UCI config
+-- @param section UCI section name
+-- @param option UCI option (optional)
+-- @return Boolean whether operation succeeded
+
+--- Call a function for every section of a certain type.
+-- @class function
+-- @name Cursor.foreach
+-- @param config UCI config
+-- @param type UCI section type
+-- @param callback Function to be called
+-- @return Boolean whether operation succeeded
+
+--- Get a section type or an option
+-- @class function
+-- @name Cursor.get
+-- @param config UCI config
+-- @param section UCI section name
+-- @param option UCI option (optional)
+-- @return UCI value
+
+--- Get all sections of a config or all values of a section.
+-- @class function
+-- @name Cursor.get_all
+-- @param config UCI config
+-- @param section UCI section name (optional)
+-- @return Table of UCI sections or table of UCI values
+
+--- Manually load a config.
+-- @class function
+-- @name Cursor.load
+-- @param config UCI config
+-- @return Boolean whether operation succeeded
+-- @see Cursor.save
+-- @see Cursor.unload
+
+--- Revert unsaved changes.
+-- @class function
+-- @name Cursor.revert
+-- @param config UCI config
+-- @return Boolean whether operation succeeded
+-- @see Cursor.commit
+
+--- Saves changes made to a config to make them committable.
+-- @class function
+-- @name Cursor.save
+-- @param config UCI config
+-- @return Boolean whether operation succeeded
+-- @see Cursor.load
+-- @see Cursor.unload
+
+--- Set a value or create a named section.
+-- @class function
+-- @name Cursor.set
+-- @param config UCI config
+-- @param section UCI section name
+-- @param option UCI option or UCI section type
+-- @param value UCI value or nil if you want to create a section
+-- @return Boolean whether operation succeeded
+
+--- Get the configuration directory.
+-- @class function
+-- @name Cursor.get_confdir
+-- @return Configuration directory
+
+--- Get the directory for uncomitted changes.
+-- @class function
+-- @name Cursor.get_savedir
+-- @return Save directory
+
+--- Set the configuration directory.
+-- @class function
+-- @name Cursor.set_confdir
+-- @param directory UCI configuration directory
+-- @return Boolean whether operation succeeded
+
+--- Set the directory for uncommited changes.
+-- @class function
+-- @name Cursor.set_savedir
+-- @param directory UCI changes directory
+-- @return Boolean whether operation succeeded
+
+--- Discard changes made to a config.
+-- @class function
+-- @name Cursor.unload
+-- @param config UCI config
+-- @return Boolean whether operation succeeded
+-- @see Cursor.load
+-- @see Cursor.save