local lpeg = require "lpeg" local string = require "string" local stringformat = string.format local verboselvl = 0 local colorize = false local table_mirrored = function (t, only) local ret = { } if t ~= nil then for k, v in next, t do ret [k] = v if only == false then ret [v] = k end end end return ret end local status do local codes = { ok = 0 , error = -1 } status = { codes = table_mirrored (codes) } end --- check if stderr is pipe; use color otherwise local ok, unistd = pcall (require, "posix.unistd") if ok then local stderr_fd = unistd.STDERR_FILENO colorize = unistd.isatty (unistd.STDERR_FILENO) == 1 end local esc = '\27[' local colors = { black = esc .. "0;30m" , red = esc .. "0;31m" , green = esc .. "0;32m" , yellow = esc .. "0;33m" , blue = esc .. "0;34m" , purple = esc .. "0;35m" , cyan = esc .. "0;36m" , white = esc .. "0;37m" , reset = esc .. "m" } local mk_out = function (stream, threshold, newlinep, pfx, color) if pfx == nil then pfx = "" else if colorize and color ~= nil then local col = colors [color] if col ~= nil then pfx = col .. pfx .. colors.reset end end pfx = "["..pfx.."] " end local out = io.stdout if stream == "err" or stream == "stderr" then out = io.stderr end return function (...) if verboselvl >= threshold then local ok, msg = pcall (stringformat, ...) if ok then out.write (out, pfx) out.write (out, msg) if newlinep == true then out:write "\n" end ---else silently ignore end end end end local set_verbosity = function (n) verboselvl = n end local trim_whitespace local unescape_string local internalize_value do local P = lpeg.P local S = lpeg.S local Cs = lpeg.Cs local p_ws_char = S" \n\r\t\v" local p_ws = p_ws_char^1 local p_ws_trailing = p_ws * P (-1) local p_ws_drop = Cs ( (p_ws^-1 / "") * (1 - p_ws_trailing)^0 * (p_ws^-1 * P (-1) / "")) local p_escape_char = (P"\\n" / "\n") + (P"\\r" / "\r") + (P"\\t" / "\t") + (P"\\v" / "\v") local p_unescape = Cs ((p_escape_char + 1)^0) --[[-- rfc2445, sec. 4.1.2: Properties can have multiple values, separated by a literal comma, thus text commas are escaped. --]]-- local p_value_char = ( p_escape_char + P"\\," / "," + P"," / "\n") local p_value = Cs ((p_value_char + 1)^0) local lpegmatch = lpeg.match trim_whitespace = function (s) return lpegmatch (p_ws_drop , s) end unescape_string = function (s) return lpegmatch (p_unescape, s) end internalize_value = function (s) return lpegmatch (p_value, s) end end return { println = mk_out ("stdout", 0, true) , errorln = mk_out ("stderr", 0, true, "error", "red") , noiseln = mk_out ("stderr", 1, true, "info" , "yellow") , debugln = mk_out ("stderr", 2, true, "debug", "purple") , set_verbosity = set_verbosity , trim_whitespace = trim_whitespace , unescape_string = unescape_string , internalize_value = internalize_value , status = status }