1do
2  local ffi = require("ffi")
3  local ptrtype = ffi.typeof("uint64_t")
4  local strformat = string.format
5  function string.format(format, ...)
6    local args = {...}
7    local match_no = 1
8    local newfmt, count = string.gsub(format, "()%%(.-)(%a)",
9      function(_, mods, t)
10        local n = match_no
11        match_no = match_no + 1
12        if t == 'p' and ffi.istype(ptrtype, args[n]) then
13          local lo = tonumber(args[n] % 4294967296ULL)
14          local hi = tonumber(args[n] / 4294967296ULL)
15          args[n] = (hi == 0) and strformat("%x", lo) or strformat("%x%08x", hi, lo)
16          return "%"..mods.."s"
17        end
18      end)
19    if count == 0 then
20      return strformat(format, ...)
21    else
22      return strformat(newfmt, unpack(args,1,select('#',...)))
23    end
24  end
25end
26
27function string.starts(s, p)
28  return string.sub(s, 1, string.len(p)) == p
29end
30
31function string.lstrip(s, p)
32  return string.sub(s, string.len(p) + 1)
33end
34
35function string.ends(s, e)
36  return e == '' or string.sub(s, -string.len(e))==e
37end
38
39function string.escape(s)
40  return s:gsub('[%-%.%+%[%]%(%)%$%^%%%?%*]','%%%1')
41end
42
43--- split a string into a list of strings separated by a delimiter.
44-- @param s The input string
45-- @param re A Lua string pattern; defaults to '%s+'
46-- @param plain don't use Lua patterns
47-- @param n optional maximum number of splits
48-- @return a list-like table
49-- @raise error if s is not a string
50function string.split(s,re,plain,n)
51  local find,sub,append = string.find, string.sub, table.insert
52  local i1,ls = 1,{}
53  if not re then re = '%s+' end
54  if re == '' then return {s} end
55  while true do
56    local i2,i3 = find(s,re,i1,plain)
57    if not i2 then
58      local last = sub(s,i1)
59      if last ~= '' then append(ls,last) end
60      if #ls == 1 and ls[1] == '' then
61        return {}
62      else
63        return ls
64      end
65    end
66    append(ls,sub(s,i1,i2-1))
67    if n and #ls == n then
68      ls[#ls] = sub(s,i1)
69      return ls
70    end
71    i1 = i3+1
72  end
73end
74
75function table.count(T)
76  local count = 0
77  for _ in pairs(T) do count = count + 1 end
78  return count
79end
80
81function table.bsearch(list, value, mkval)
82  local low = 1
83  local high = #list
84  while low <= high do
85    local mid = math.floor((low+high)/2)
86    local this = mkval and mkval(list[mid]) or list[mid]
87    if this > value then
88      high = mid - 1
89    elseif this < value then
90      low = mid + 1
91    else
92      return mid
93    end
94  end
95  return low - 1
96end
97
98function table.join(a, b)
99  assert(a)
100  if b == nil or #b == 0 then
101    return a
102  end
103
104  local res = {}
105  for _, v in ipairs(a) do
106    table.insert(res, v)
107  end
108  for _, v in ipairs(b) do
109    table.insert(res, v)
110  end
111  return res
112end
113
114function table.build(iterator_fn, build_fn)
115  build_fn = (build_fn or function(arg) return arg end)
116  local res = {}
117  while true do
118    local vars = {iterator_fn()}
119    if vars[1] == nil then break end
120    table.insert(res, build_fn(vars))
121  end
122  return res
123end
124
125function table.values(T)
126  local V = {}
127  for k, v in pairs(T) do
128    table.insert(V, v)
129  end
130  return V
131end
132
133function table.tuples(T)
134  local i = 0
135  local n = table.getn(t)
136  return function ()
137    i = i + 1
138    if i <= n then return t[i][1], t[i][2] end
139  end
140end
141
142getmetatable("").__mod = function(a, b)
143  if not b then
144    return a
145  elseif type(b) == "table" then
146    return string.format(a, unpack(b))
147  else
148    return string.format(a, b)
149  end
150end
151
152function os.exists(path)
153  local f=io.open(path,"r")
154  if f~=nil then
155    io.close(f)
156    return true
157  else
158    return false
159  end
160end
161
162function os.spawn(...)
163  local cmd = string.format(...)
164  local proc = assert(io.popen(cmd))
165  local out = proc:read("*a")
166  proc:close()
167  return out
168end
169
170local function logline(...)
171  if not log.enabled then
172    return
173  end
174
175  local c_green = "\27[32m"
176  local c_grey = "\27[1;30m"
177  local c_clear = "\27[0m"
178
179  local msg = string.format(...)
180  local info = debug.getinfo(2, "Sln")
181  local line = string.format("%s[%s:%s]%s %s", c_grey,
182    info.short_src:match("^.+/(.+)$"), info.currentline, c_clear, info.name)
183
184  io.stderr:write(
185    string.format("%s[%s]%s %s: %s\n", c_green,
186      os.date("%H:%M:%S"), c_clear, line, msg))
187end
188
189setmetatable(_G, {
190  __newindex = function (_, n)
191    error("attempt to write to undeclared variable "..n, 2)
192  end,
193  __index = function (_, n)
194    error("attempt to read undeclared variable "..n, 2)
195  end,
196})
197
198rawset(_G, "log", { info = logline, enabled = false })
199rawset(_G, "class", require("bcc.vendor.middleclass"))
200