summaryrefslogtreecommitdiffstats
path: root/ctl-lib/ctl-lua-utils.c
blob: 5c96226274aefea3f51c20fc268e72976abcefcb (plain) <
/*
 * Copyright (C) 2016 \"IoT.bzh\"
 * Author Fulup Ar Foll <fulup@iot.bzh>
 *
  Licensed under the Apache License, Version 2.0 (the \"License\");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an \"AS IS\" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ref:
 *  (manual) https://www.lua.org/manual/5.3/manual.html
 *  (lua->C) http://www.troubleshooters.com/codecorn/lua/lua_c_calls_lua.htm#_Anatomy_of_a_Lua_Call
 *  (lua/C Var) http://acamara.es/blog/2012/08/passing-variables-from-lua-5-2-to-c-and-vice-versa/
 *  (Lua/C Lib)https://john.nachtimwald.com/2014/07/12/wrapping-a-c-library-in-lua/
 *  (Lua/C Table) https://gist.github.com/SONIC3D/10388137
 *  (Lua/C Nested table) https://stackoverflow.com/questions/45699144/lua-nested-table-from-lua-to-c
 *  (Lua/C Wrapper) https://stackoverflow.com/questions/45699950/lua-passing-handle-to-function-created-with-newlib
 *
 */

const char *lua_utils = "--===================================================\n\
--=  Niklas Frykholm\n\
-- basically if user tries to create global variable\n\
-- the system will not let them!!\n\
-- call GLOBAL_lock(_G)\n\
-- \n\
--===================================================\n\
function GLOBAL_lock(t)\n\
  local mt = getmetatable(t) or {}\n\
  mt.__newindex = lock_new_index\n\
  setmetatable(t, mt)\n\
end\n\
\n\
--===================================================\n\
-- call GLOBAL_unlock(_G)\n\
-- to change things back to normal.\n\
--===================================================\n\
function GLOBAL_unlock(t)\n\
  local mt = getmetatable(t) or {}\n\
  mt.__newindex = unlock_new_index\n\
  setmetatable(t, mt)\n\
end\n\
\n\
function lock_new_index(t, k, v)\n\
  if (string.sub(k,1,1) ~= \"_\") then\n\
    GLOBAL_unlock(_G)\n\
    error(\"GLOBALS are locked -- \" .. k ..\n\
          \" must be declared local or prefix with '_' for globals.\", 2)\n\
  else\n\
    rawset(t, k, v)\n\
  end\n\
end\n\
\n\
function unlock_new_index(t, k, v)\n\
  rawset(t, k, v)\n\
end\n\
\n\
-- return serialised version of printable table\n\
function Dump_Table(o)\n\
   if type(o) == 'table' then\n\
      local s = '{ '\n\
      for k,v in pairs(o) do\n\
         if type(k) ~= 'number' then k = '\"'..k..'\"' end\n\
         s = s .. '['..k..'] = ' .. Dump_Table(v) .. ','\
      end\n\
      return s .. '} '\n\
   else\n\
      return tostring(o)\n\
   end\n\
end\n\
\n\
-- simulate C prinf function\n\
printf = function(s,...)\n\
    io.write(s:format(...))\n\
    io.write(\"\")\n\
    return\n\
end\n\
\n\
function sleep(n)\n\
    os.execute(\"sleep \" .. tonumber(n))\n\
end\n\
\n\
function table_size(t)\n\
	local size = 0\n\
	for _ in pairs(t) do\n\
		size = size + 1\n\
	end\n\
	return size\n\
end\n\
function deep_copy(orig)\n\
    local orig_type = type(orig)\n\
    local copy\n\
    if orig_type == 'table' then\n\
        copy = {}\n\
        for orig_key, orig_value in next, orig, nil do\n\
            copy[deep_copy(orig_key)] = deep_copy(orig_value)\n\
        end\n\
        setmetatable(copy, deep_copy(getmetatable(orig)))\n\
    else -- number, string, boolean, etc\n\
        copy = orig\n\
    end\n\
    return copy\n\
end\n\
function table_eq(table1, table2)\n\
	local avoid_loops = {}\n\
	local function recurse(t1, t2)\n\
	-- compare value types\n\
	if type(t1) ~= type(t2) then return false end\n\
	-- Base case: compare simple values\n\
	if type(t1) ~= \"table\" then return t1 == t2 end\n\
	-- Now, on to tables.\n\
	-- First, let's avoid looping forever.\n\
	if avoid_loops[t1] then return avoid_loops[t1] == t2 end\n\
	avoid_loops[t1] = t2\n\
	-- Copy keys from t2\n\
	local t2keys = {}\n\
	local t2tablekeys = {}\n\
	for k, _ in pairs(t2) do\n\
	if type(k) == \"table\" then table.insert(t2tablekeys, k) end\n\
	t2keys[k] = true\n\
	end\n\
	-- Let's iterate keys from t1\n\
	for k1, v1 in pairs(t1) do\n\
	local v2 = t2[k1]\n\
	if type(k1) == \"table\" then\n\
		-- if key is a table, we need to find an equivalent one.\n\
		local ok = false\n\
		for i, tk in ipairs(t2tablekeys) do\n\
		if table_eq(k1, tk) and recurse(v1, t2[tk]) then\n\
		table.remove(t2tablekeys, i)\n\
		t2keys[tk] = nil\n\
		ok = true\n\
		break\n\
		end\n\
		end\n\
		if not ok then return false end\n\
	else\n\
		-- t1 has a key which t2 doesn't have, fail.\n\
		if v2 == nil then return false end\n\
		t2keys[k1] = nil\n\
		if not recurse(v1, v2) then return false end\n\
	end\n\
	end\n\
	-- if t2 has a key which t1 doesn't have, fail.\n\
	if next(t2keys) then return false end\n\
	return true\n\
	end\n\
	return recurse(table1, table2)\n\
end\n\
-- lock global variable\n\
GLOBAL_lock(_G)\n\
";