summaryrefslogtreecommitdiff
path: root/common.lua
blob: 89153d8f49fc995292e4d8884627970259fd4bc7 (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
local lpeg          = require "lpeg"

local string        = require "string"
local stringformat  = string.format

local verboselvl    = 0
local colorize      = false

--- 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
  }