luci-base: add luci.util.serialize_json()
[project/luci.git] / modules / luci-base / luasrc / util.lua
1 -- Copyright 2008 Steven Barth <steven@midlink.org>
2 -- Licensed to the public under the Apache License 2.0.
3
4 local io = require "io"
5 local math = require "math"
6 local table = require "table"
7 local debug = require "debug"
8 local ldebug = require "luci.debug"
9 local string = require "string"
10 local coroutine = require "coroutine"
11 local tparser = require "luci.template.parser"
12
13 local _ubus = require "ubus"
14 local _ubus_connection = nil
15
16 local getmetatable, setmetatable = getmetatable, setmetatable
17 local rawget, rawset, unpack = rawget, rawset, unpack
18 local tostring, type, assert = tostring, type, assert
19 local ipairs, pairs, next, loadstring = ipairs, pairs, next, loadstring
20 local require, pcall, xpcall = require, pcall, xpcall
21 local collectgarbage, get_memory_limit = collectgarbage, get_memory_limit
22
23 --- LuCI utility functions.
24 module "luci.util"
25
26 --
27 -- Pythonic string formatting extension
28 --
29 getmetatable("").__mod = function(a, b)
30         if not b then
31                 return a
32         elseif type(b) == "table" then
33                 for k, _ in pairs(b) do if type(b[k]) == "userdata" then b[k] = tostring(b[k]) end end
34                 return a:format(unpack(b))
35         else
36                 if type(b) == "userdata" then b = tostring(b) end
37                 return a:format(b)
38         end
39 end
40
41
42 --
43 -- Class helper routines
44 --
45
46 -- Instantiates a class
47 local function _instantiate(class, ...)
48         local inst = setmetatable({}, {__index = class})
49
50         if inst.__init__ then
51                 inst:__init__(...)
52         end
53
54         return inst
55 end
56
57 --- Create a Class object (Python-style object model).
58 -- The class object can be instantiated by calling itself.
59 -- Any class functions or shared parameters can be attached to this object.
60 -- Attaching a table to the class object makes this table shared between
61 -- all instances of this class. For object parameters use the __init__ function.
62 -- Classes can inherit member functions and values from a base class.
63 -- Class can be instantiated by calling them. All parameters will be passed
64 -- to the __init__ function of this class - if such a function exists.
65 -- The __init__ function must be used to set any object parameters that are not shared
66 -- with other objects of this class. Any return values will be ignored.
67 -- @param base  The base class to inherit from (optional)
68 -- @return              A class object
69 -- @see                 instanceof
70 -- @see                 clone
71 function class(base)
72         return setmetatable({}, {
73                 __call  = _instantiate,
74                 __index = base
75         })
76 end
77
78 --- Test whether the given object is an instance of the given class.
79 -- @param object        Object instance
80 -- @param class         Class object to test against
81 -- @return                      Boolean indicating whether the object is an instance
82 -- @see                         class
83 -- @see                         clone
84 function instanceof(object, class)
85         local meta = getmetatable(object)
86         while meta and meta.__index do
87                 if meta.__index == class then
88                         return true
89                 end
90                 meta = getmetatable(meta.__index)
91         end
92         return false
93 end
94
95
96 --
97 -- Scope manipulation routines
98 --
99
100 local tl_meta = {
101         __mode = "k",
102
103         __index = function(self, key)
104                 local t = rawget(self, coxpt[coroutine.running()]
105                  or coroutine.running() or 0)
106                 return t and t[key]
107         end,
108
109         __newindex = function(self, key, value)
110                 local c = coxpt[coroutine.running()] or coroutine.running() or 0
111                 local r = rawget(self, c)
112                 if not r then
113                         rawset(self, c, { [key] = value })
114                 else
115                         r[key] = value
116                 end
117         end
118 }
119
120 --- Create a new or get an already existing thread local store associated with
121 -- the current active coroutine. A thread local store is private a table object
122 -- whose values can't be accessed from outside of the running coroutine.
123 -- @return      Table value representing the corresponding thread local store
124 function threadlocal(tbl)
125         return setmetatable(tbl or {}, tl_meta)
126 end
127
128
129 --
130 -- Debugging routines
131 --
132
133 --- Write given object to stderr.
134 -- @param obj   Value to write to stderr
135 -- @return              Boolean indicating whether the write operation was successful
136 function perror(obj)
137         return io.stderr:write(tostring(obj) .. "\n")
138 end
139
140 --- Recursively dumps a table to stdout, useful for testing and debugging.
141 -- @param t     Table value to dump
142 -- @param maxdepth      Maximum depth
143 -- @return      Always nil
144 function dumptable(t, maxdepth, i, seen)
145         i = i or 0
146         seen = seen or setmetatable({}, {__mode="k"})
147
148         for k,v in pairs(t) do
149                 perror(string.rep("\t", i) .. tostring(k) .. "\t" .. tostring(v))
150                 if type(v) == "table" and (not maxdepth or i < maxdepth) then
151                         if not seen[v] then
152                                 seen[v] = true
153                                 dumptable(v, maxdepth, i+1, seen)
154                         else
155                                 perror(string.rep("\t", i) .. "*** RECURSION ***")
156                         end
157                 end
158         end
159 end
160
161
162 --
163 -- String and data manipulation routines
164 --
165
166 --- Create valid XML PCDATA from given string.
167 -- @param value String value containing the data to escape
168 -- @return              String value containing the escaped data
169 function pcdata(value)
170         return value and tparser.pcdata(tostring(value))
171 end
172
173 --- Strip HTML tags from given string.
174 -- @param value String containing the HTML text
175 -- @return      String with HTML tags stripped of
176 function striptags(value)
177         return value and tparser.striptags(tostring(value))
178 end
179
180 --- Splits given string on a defined separator sequence and return a table
181 -- containing the resulting substrings. The optional max parameter specifies
182 -- the number of bytes to process, regardless of the actual length of the given
183 -- string. The optional last parameter, regex, specifies whether the separator
184 -- sequence is interpreted as regular expression.
185 -- @param str           String value containing the data to split up
186 -- @param pat           String with separator pattern (optional, defaults to "\n")
187 -- @param max           Maximum times to split (optional)
188 -- @param regex         Boolean indicating whether to interpret the separator
189 --                                      pattern as regular expression (optional, default is false)
190 -- @return                      Table containing the resulting substrings
191 function split(str, pat, max, regex)
192         pat = pat or "\n"
193         max = max or #str
194
195         local t = {}
196         local c = 1
197
198         if #str == 0 then
199                 return {""}
200         end
201
202         if #pat == 0 then
203                 return nil
204         end
205
206         if max == 0 then
207                 return str
208         end
209
210         repeat
211                 local s, e = str:find(pat, c, not regex)
212                 max = max - 1
213                 if s and max < 0 then
214                         t[#t+1] = str:sub(c)
215                 else
216                         t[#t+1] = str:sub(c, s and s - 1)
217                 end
218                 c = e and e + 1 or #str + 1
219         until not s or max < 0
220
221         return t
222 end
223
224 --- Remove leading and trailing whitespace from given string value.
225 -- @param str   String value containing whitespace padded data
226 -- @return              String value with leading and trailing space removed
227 function trim(str)
228         return (str:gsub("^%s*(.-)%s*$", "%1"))
229 end
230
231 --- Count the occurences of given substring in given string.
232 -- @param str           String to search in
233 -- @param pattern       String containing pattern to find
234 -- @return                      Number of found occurences
235 function cmatch(str, pat)
236         local count = 0
237         for _ in str:gmatch(pat) do count = count + 1 end
238         return count
239 end
240
241 --- Return a matching iterator for the given value. The iterator will return
242 -- one token per invocation, the tokens are separated by whitespace. If the
243 -- input value is a table, it is transformed into a string first. A nil value
244 -- will result in a valid interator which aborts with the first invocation.
245 -- @param val           The value to scan (table, string or nil)
246 -- @return                      Iterator which returns one token per call
247 function imatch(v)
248         if type(v) == "table" then
249                 local k = nil
250                 return function()
251                         k = next(v, k)
252                         return v[k]
253                 end
254
255         elseif type(v) == "number" or type(v) == "boolean" then
256                 local x = true
257                 return function()
258                         if x then
259                                 x = false
260                                 return tostring(v)
261                         end
262                 end
263
264         elseif type(v) == "userdata" or type(v) == "string" then
265                 return tostring(v):gmatch("%S+")
266         end
267
268         return function() end
269 end
270
271 --- Parse certain units from the given string and return the canonical integer
272 -- value or 0 if the unit is unknown. Upper- or lower case is irrelevant.
273 -- Recognized units are:
274 --      o "y"   - one year   (60*60*24*366)
275 --  o "m"       - one month  (60*60*24*31)
276 --  o "w"       - one week   (60*60*24*7)
277 --  o "d"       - one day    (60*60*24)
278 --  o "h"       - one hour       (60*60)
279 --  o "min"     - one minute (60)
280 --  o "kb"  - one kilobyte (1024)
281 --  o "mb"      - one megabyte (1024*1024)
282 --  o "gb"      - one gigabyte (1024*1024*1024)
283 --  o "kib" - one si kilobyte (1000)
284 --  o "mib"     - one si megabyte (1000*1000)
285 --  o "gib"     - one si gigabyte (1000*1000*1000)
286 -- @param ustr  String containing a numerical value with trailing unit
287 -- @return              Number containing the canonical value
288 function parse_units(ustr)
289
290         local val = 0
291
292         -- unit map
293         local map = {
294                 -- date stuff
295                 y   = 60 * 60 * 24 * 366,
296                 m   = 60 * 60 * 24 * 31,
297                 w   = 60 * 60 * 24 * 7,
298                 d   = 60 * 60 * 24,
299                 h   = 60 * 60,
300                 min = 60,
301
302                 -- storage sizes
303                 kb  = 1024,
304                 mb  = 1024 * 1024,
305                 gb  = 1024 * 1024 * 1024,
306
307                 -- storage sizes (si)
308                 kib = 1000,
309                 mib = 1000 * 1000,
310                 gib = 1000 * 1000 * 1000
311         }
312
313         -- parse input string
314         for spec in ustr:lower():gmatch("[0-9%.]+[a-zA-Z]*") do
315
316                 local num = spec:gsub("[^0-9%.]+$","")
317                 local spn = spec:gsub("^[0-9%.]+", "")
318
319                 if map[spn] or map[spn:sub(1,1)] then
320                         val = val + num * ( map[spn] or map[spn:sub(1,1)] )
321                 else
322                         val = val + num
323                 end
324         end
325
326
327         return val
328 end
329
330 -- also register functions above in the central string class for convenience
331 string.pcdata      = pcdata
332 string.striptags   = striptags
333 string.split       = split
334 string.trim        = trim
335 string.cmatch      = cmatch
336 string.parse_units = parse_units
337
338
339 --- Appends numerically indexed tables or single objects to a given table.
340 -- @param src   Target table
341 -- @param ...   Objects to insert
342 -- @return              Target table
343 function append(src, ...)
344         for i, a in ipairs({...}) do
345                 if type(a) == "table" then
346                         for j, v in ipairs(a) do
347                                 src[#src+1] = v
348                         end
349                 else
350                         src[#src+1] = a
351                 end
352         end
353         return src
354 end
355
356 --- Combines two or more numerically indexed tables and single objects into one table.
357 -- @param tbl1  Table value to combine
358 -- @param tbl2  Table value to combine
359 -- @param ...   More tables to combine
360 -- @return              Table value containing all values of given tables
361 function combine(...)
362         return append({}, ...)
363 end
364
365 --- Checks whether the given table contains the given value.
366 -- @param table Table value
367 -- @param value Value to search within the given table
368 -- @return              Boolean indicating whether the given value occurs within table
369 function contains(table, value)
370         for k, v in pairs(table) do
371                 if value == v then
372                         return k
373                 end
374         end
375         return false
376 end
377
378 --- Update values in given table with the values from the second given table.
379 -- Both table are - in fact - merged together.
380 -- @param t                     Table which should be updated
381 -- @param updates       Table containing the values to update
382 -- @return                      Always nil
383 function update(t, updates)
384         for k, v in pairs(updates) do
385                 t[k] = v
386         end
387 end
388
389 --- Retrieve all keys of given associative table.
390 -- @param t     Table to extract keys from
391 -- @return      Sorted table containing the keys
392 function keys(t)
393         local keys = { }
394         if t then
395                 for k, _ in kspairs(t) do
396                         keys[#keys+1] = k
397                 end
398         end
399         return keys
400 end
401
402 --- Clones the given object and return it's copy.
403 -- @param object        Table value to clone
404 -- @param deep          Boolean indicating whether to do recursive cloning
405 -- @return                      Cloned table value
406 function clone(object, deep)
407         local copy = {}
408
409         for k, v in pairs(object) do
410                 if deep and type(v) == "table" then
411                         v = clone(v, deep)
412                 end
413                 copy[k] = v
414         end
415
416         return setmetatable(copy, getmetatable(object))
417 end
418
419
420 --- Create a dynamic table which automatically creates subtables.
421 -- @return      Dynamic Table
422 function dtable()
423         return setmetatable({}, { __index =
424                 function(tbl, key)
425                         return rawget(tbl, key)
426                          or rawget(rawset(tbl, key, dtable()), key)
427                 end
428         })
429 end
430
431
432 -- Serialize the contents of a table value.
433 function _serialize_table(t, seen)
434         assert(not seen[t], "Recursion detected.")
435         seen[t] = true
436
437         local data  = ""
438         local idata = ""
439         local ilen  = 0
440
441         for k, v in pairs(t) do
442                 if type(k) ~= "number" or k < 1 or math.floor(k) ~= k or ( k - #t ) > 3 then
443                         k = serialize_data(k, seen)
444                         v = serialize_data(v, seen)
445                         data = data .. ( #data > 0 and ", " or "" ) ..
446                                 '[' .. k .. '] = ' .. v
447                 elseif k > ilen then
448                         ilen = k
449                 end
450         end
451
452         for i = 1, ilen do
453                 local v = serialize_data(t[i], seen)
454                 idata = idata .. ( #idata > 0 and ", " or "" ) .. v
455         end
456
457         return idata .. ( #data > 0 and #idata > 0 and ", " or "" ) .. data
458 end
459
460 --- Recursively serialize given data to lua code, suitable for restoring
461 -- with loadstring().
462 -- @param val   Value containing the data to serialize
463 -- @return              String value containing the serialized code
464 -- @see                 restore_data
465 -- @see                 get_bytecode
466 function serialize_data(val, seen)
467         seen = seen or setmetatable({}, {__mode="k"})
468
469         if val == nil then
470                 return "nil"
471         elseif type(val) == "number" then
472                 return val
473         elseif type(val) == "string" then
474                 return "%q" % val
475         elseif type(val) == "boolean" then
476                 return val and "true" or "false"
477         elseif type(val) == "function" then
478                 return "loadstring(%q)" % get_bytecode(val)
479         elseif type(val) == "table" then
480                 return "{ " .. _serialize_table(val, seen) .. " }"
481         else
482                 return '"[unhandled data type:' .. type(val) .. ']"'
483         end
484 end
485
486 --- Restore data previously serialized with serialize_data().
487 -- @param str   String containing the data to restore
488 -- @return              Value containing the restored data structure
489 -- @see                 serialize_data
490 -- @see                 get_bytecode
491 function restore_data(str)
492         return loadstring("return " .. str)()
493 end
494
495
496 --
497 -- Byte code manipulation routines
498 --
499
500 --- Return the current runtime bytecode of the given data. The byte code
501 -- will be stripped before it is returned.
502 -- @param val   Value to return as bytecode
503 -- @return              String value containing the bytecode of the given data
504 function get_bytecode(val)
505         local code
506
507         if type(val) == "function" then
508                 code = string.dump(val)
509         else
510                 code = string.dump( loadstring( "return " .. serialize_data(val) ) )
511         end
512
513         return code -- and strip_bytecode(code)
514 end
515
516 --- Strips unnescessary lua bytecode from given string. Information like line
517 -- numbers and debugging numbers will be discarded. Original version by
518 -- Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html)
519 -- @param code  String value containing the original lua byte code
520 -- @return              String value containing the stripped lua byte code
521 function strip_bytecode(code)
522         local version, format, endian, int, size, ins, num, lnum = code:byte(5, 12)
523         local subint
524         if endian == 1 then
525                 subint = function(code, i, l)
526                         local val = 0
527                         for n = l, 1, -1 do
528                                 val = val * 256 + code:byte(i + n - 1)
529                         end
530                         return val, i + l
531                 end
532         else
533                 subint = function(code, i, l)
534                         local val = 0
535                         for n = 1, l, 1 do
536                                 val = val * 256 + code:byte(i + n - 1)
537                         end
538                         return val, i + l
539                 end
540         end
541
542         local function strip_function(code)
543                 local count, offset = subint(code, 1, size)
544                 local stripped = { string.rep("\0", size) }
545                 local dirty = offset + count
546                 offset = offset + count + int * 2 + 4
547                 offset = offset + int + subint(code, offset, int) * ins
548                 count, offset = subint(code, offset, int)
549                 for n = 1, count do
550                         local t
551                         t, offset = subint(code, offset, 1)
552                         if t == 1 then
553                                 offset = offset + 1
554                         elseif t == 4 then
555                                 offset = offset + size + subint(code, offset, size)
556                         elseif t == 3 then
557                                 offset = offset + num
558                         elseif t == 254 or t == 9 then
559                                 offset = offset + lnum
560                         end
561                 end
562                 count, offset = subint(code, offset, int)
563                 stripped[#stripped+1] = code:sub(dirty, offset - 1)
564                 for n = 1, count do
565                         local proto, off = strip_function(code:sub(offset, -1))
566                         stripped[#stripped+1] = proto
567                         offset = offset + off - 1
568                 end
569                 offset = offset + subint(code, offset, int) * int + int
570                 count, offset = subint(code, offset, int)
571                 for n = 1, count do
572                         offset = offset + subint(code, offset, size) + size + int * 2
573                 end
574                 count, offset = subint(code, offset, int)
575                 for n = 1, count do
576                         offset = offset + subint(code, offset, size) + size
577                 end
578                 stripped[#stripped+1] = string.rep("\0", int * 3)
579                 return table.concat(stripped), offset
580         end
581
582         return code:sub(1,12) .. strip_function(code:sub(13,-1))
583 end
584
585
586 --
587 -- Sorting iterator functions
588 --
589
590 function _sortiter( t, f )
591         local keys = { }
592
593         local k, v
594         for k, v in pairs(t) do
595                 keys[#keys+1] = k
596         end
597
598         local _pos = 0
599
600         table.sort( keys, f )
601
602         return function()
603                 _pos = _pos + 1
604                 if _pos <= #keys then
605                         return keys[_pos], t[keys[_pos]], _pos
606                 end
607         end
608 end
609
610 --- Return a key, value iterator which returns the values sorted according to
611 -- the provided callback function.
612 -- @param t     The table to iterate
613 -- @param f A callback function to decide the order of elements
614 -- @return      Function value containing the corresponding iterator
615 function spairs(t,f)
616         return _sortiter( t, f )
617 end
618
619 --- Return a key, value iterator for the given table.
620 -- The table pairs are sorted by key.
621 -- @param t     The table to iterate
622 -- @return      Function value containing the corresponding iterator
623 function kspairs(t)
624         return _sortiter( t )
625 end
626
627 --- Return a key, value iterator for the given table.
628 -- The table pairs are sorted by value.
629 -- @param t     The table to iterate
630 -- @return      Function value containing the corresponding iterator
631 function vspairs(t)
632         return _sortiter( t, function (a,b) return t[a] < t[b] end )
633 end
634
635
636 --
637 -- System utility functions
638 --
639
640 --- Test whether the current system is operating in big endian mode.
641 -- @return      Boolean value indicating whether system is big endian
642 function bigendian()
643         return string.byte(string.dump(function() end), 7) == 0
644 end
645
646 --- Execute given commandline and gather stdout.
647 -- @param command       String containing command to execute
648 -- @return                      String containing the command's stdout
649 function exec(command)
650         local pp   = io.popen(command)
651         local data = pp:read("*a")
652         pp:close()
653
654         return data
655 end
656
657 --- Return a line-buffered iterator over the output of given command.
658 -- @param command       String containing the command to execute
659 -- @return                      Iterator
660 function execi(command)
661         local pp = io.popen(command)
662
663         return pp and function()
664                 local line = pp:read()
665
666                 if not line then
667                         pp:close()
668                 end
669
670                 return line
671         end
672 end
673
674 -- Deprecated
675 function execl(command)
676         local pp   = io.popen(command)
677         local line = ""
678         local data = {}
679
680         while true do
681                 line = pp:read()
682                 if (line == nil) then break end
683                 data[#data+1] = line
684         end
685         pp:close()
686
687         return data
688 end
689
690 --- Issue an ubus call.
691 -- @param object                String containing the ubus object to call
692 -- @param method                String containing the ubus method to call
693 -- @param values                Table containing the values to pass
694 -- @return                      Table containin the ubus result
695 function ubus(object, method, data)
696         if not _ubus_connection then
697                 _ubus_connection = _ubus.connect()
698                 assert(_ubus_connection, "Unable to establish ubus connection")
699         end
700
701         if object and method then
702                 if type(data) ~= "table" then
703                         data = { }
704                 end
705                 return _ubus_connection:call(object, method, data)
706         elseif object then
707                 return _ubus_connection:signatures(object)
708         else
709                 return _ubus_connection:objects()
710         end
711 end
712
713 --- Convert data structure to JSON
714 -- @param data          The data to serialize
715 -- @param writer        A function to write a chunk of JSON data (optional)
716 -- @return                      String containing the JSON if called without write callback
717 function serialize_json(x, cb)
718         local rv, push = nil, cb
719         if not push then
720                 rv = { }
721                 push = function(tok) rv[#rv+1] = tok end
722         end
723
724         if x == nil then
725                 push("null")
726         elseif type(x) == "table" then
727                 -- test if table is array like
728                 local k, v
729                 local n1, n2 = 0, 0
730                 for k in pairs(x) do n1 = n1 + 1 end
731                 for k in ipairs(x) do n2 = n2 + 1 end
732
733                 if n1 == n2 and n1 > 0 then
734                         push("[")
735                         for k = 1, n2 do
736                                 if k > 1 then
737                                         push(",")
738                                 end
739                                 serialize_json(x[k], push)
740                         end
741                         push("]")
742                 else
743                         push("{")
744                         for k, v in pairs(x) do
745                                 push("%q:" % tostring(k))
746                                 serialize_json(v, push)
747                                 if next(x, k) then
748                                         push(",")
749                                 end
750                         end
751                         push("}")
752                 end
753         elseif type(x) == "number" or type(x) == "boolean" then
754                 if (x ~= x) then
755                         -- NaN is the only value that doesn't equal to itself.
756                         push("Number.NaN")
757                 else
758                         push(tostring(x))
759                 end
760         else
761                 push('"%s"' % tostring(x):gsub('["%z\1-\31]',
762                         function(c) return '\\u%04x' % c:byte(1) end))
763         end
764
765         if not cb then
766                 return table.concat(rv, "")
767         end
768 end
769
770
771 --- Returns the absolute path to LuCI base directory.
772 -- @return              String containing the directory path
773 function libpath()
774         return require "nixio.fs".dirname(ldebug.__file__)
775 end
776
777
778 --
779 -- Coroutine safe xpcall and pcall versions modified for Luci
780 -- original version:
781 -- coxpcall 1.13 - Copyright 2005 - Kepler Project (www.keplerproject.org)
782 --
783 -- Copyright © 2005 Kepler Project.
784 -- Permission is hereby granted, free of charge, to any person obtaining a
785 -- copy of this software and associated documentation files (the "Software"),
786 -- to deal in the Software without restriction, including without limitation
787 -- the rights to use, copy, modify, merge, publish, distribute, sublicense,
788 -- and/or sell copies of the Software, and to permit persons to whom the
789 -- Software is furnished to do so, subject to the following conditions:
790 --
791 -- The above copyright notice and this permission notice shall be
792 -- included in all copies or substantial portions of the Software.
793 --
794 -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
795 -- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
796 -- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
797 -- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
798 -- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
799 -- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
800 -- OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
801
802 local performResume, handleReturnValue
803 local oldpcall, oldxpcall = pcall, xpcall
804 coxpt = {}
805 setmetatable(coxpt, {__mode = "kv"})
806
807 -- Identity function for copcall
808 local function copcall_id(trace, ...)
809   return ...
810 end
811
812 --- This is a coroutine-safe drop-in replacement for Lua's "xpcall"-function
813 -- @param f             Lua function to be called protected
814 -- @param err   Custom error handler
815 -- @param ...   Parameters passed to the function
816 -- @return              A boolean whether the function call succeeded and the return
817 --                              values of either the function or the error handler
818 function coxpcall(f, err, ...)
819         local res, co = oldpcall(coroutine.create, f)
820         if not res then
821                 local params = {...}
822                 local newf = function() return f(unpack(params)) end
823                 co = coroutine.create(newf)
824         end
825         local c = coroutine.running()
826         coxpt[co] = coxpt[c] or c or 0
827
828         return performResume(err, co, ...)
829 end
830
831 --- This is a coroutine-safe drop-in replacement for Lua's "pcall"-function
832 -- @param f             Lua function to be called protected
833 -- @param ...   Parameters passed to the function
834 -- @return              A boolean whether the function call succeeded and the returns
835 --                              values of the function or the error object
836 function copcall(f, ...)
837         return coxpcall(f, copcall_id, ...)
838 end
839
840 -- Handle return value of protected call
841 function handleReturnValue(err, co, status, ...)
842         if not status then
843                 return false, err(debug.traceback(co, (...)), ...)
844         end
845
846         if coroutine.status(co) ~= 'suspended' then
847                 return true, ...
848         end
849
850         return performResume(err, co, coroutine.yield(...))
851 end
852
853 -- Resume execution of protected function call
854 function performResume(err, co, ...)
855         return handleReturnValue(err, co, coroutine.resume(co, ...))
856 end