--- Useful error stack objects -- -- Many NSE library functions return a boolean status and an optional error -- message. The Oops library consists of several simple functions to accumulate -- these errors and pass them up the stack, resulting in a useful and verbose -- error message when debugging. -- -- @author Daniel Miller -- @copyright Same as Nmap--See https://nmap.org/book/man-legal.html -- @class module -- @name oops local require = require local setmetatable = setmetatable local _ENV = require "strict" {} local nmap = require "nmap" local debugging = nmap.debugging local verbosity = nmap.verbosity local table = require "table" local concat = table.concat local insert = table.insert local Oops = { new = function (self, message) local o = {message} setmetatable(o, self) self.__index = self return o end, push = function (self, message) insert(self, 1, message) end, __tostring = function (self) local banner = "The script encountered an error" local sep = ":\n- " if debugging() > 0 then -- Print full error trace return banner .. sep .. concat(self, sep) end if verbosity() > 0 then -- Show just the top error return banner .. ": " .. self[1] end -- By default, no string output shown. return "" end, } --- Add an error message to a stack of errors -- -- @param message The error message to add to the stack. -- @param previous (Optional) Any error reported by other functions that failed. -- @return An Oops object representing the error stack. err = function (message, previous) local result if previous then if previous.push then result = previous else result = Oops:new(previous) end result:push(message) elseif message.push then result = message else result = Oops:new(message) end return result end local err = err --- Report an error or return a good value -- -- If the status is true, just return the message. If it's false, return the -- message as an Oops object. This can be easily used as the final return value -- of a script. -- @param status The return status of the script. -- @param message The output of the script, or an error message if status is false. -- @return The message if status is true, or an error message if it is false. output = function (status, message) if status then return message else return err(message) end end local output = output --- Report a status and error or return values -- -- This is intended to wrap a function that returns a status and either an -- error or some value. If the status is false, the message is added to the -- stack of errors. Instead of this code: -- -- -- local status, value_or_error, value = somefunction(args) -- if not status then -- return status, "somefunction failed for some reason" -- end -- -- -- with this instead: -- -- -- local status, value_or_error, value = oops.raise("somefunction failed", somefunction(args)) -- if not status then -- return status, value_or_error -- end -- -- -- but instead of just the one error, you get a stack of errors from -- somefunction with your own message at the top. -- -- @param message The error message to report if status is false. -- @param status The first return value of the function. Treated as boolean, but returned unmodified. -- @param previous The second return value of the function, or error. -- @return The same status that was input. -- @return The rest of the return values, but on error, the message will be added to the stack. raise = function (message, status, previous, ...) local r = previous if not status then r = err(message, previous) end return status, r, ... end return _ENV