summaryrefslogtreecommitdiff
path: root/common.lua
blob: d7d3640e0ea7df443254c6a562ee8dd8cccbde47 (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
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
  }