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