From ffbbfef499c25fa382271c89b42401e3423df503 Mon Sep 17 00:00:00 2001 From: Jon Michael Aanes Date: Tue, 4 Apr 2017 16:19:22 +0200 Subject: [PATCH] Beginning work on more advanced cdata inspection. --- cdata.lua | 83 ++++++++++++++++++++++++++++++++++++++++++++ pretty.lua | 8 ++++- test/test_pretty.lua | 32 +++++++++++++---- 3 files changed, 116 insertions(+), 7 deletions(-) create mode 100644 cdata.lua diff --git a/cdata.lua b/cdata.lua new file mode 100644 index 0000000..ac12575 --- /dev/null +++ b/cdata.lua @@ -0,0 +1,83 @@ + +-- Import + +local ffi = require 'ffi' + +-- Constants + +-------------------------------------------------------------------------------- +-- Util + +local NUMBER_TO_HEX = { + [00] = '0', [01] = '1', [02] = '2', [03] = '3', [04] = '4', [05] = '5', + [06] = '6', [07] = '7', [08] = '8', [09] = '9', [10] = 'A', [11] = 'B', + [12] = 'C', [13] = 'D', [14] = 'E', [15] = 'F', +} + +local function to_hex (str) + local l = {} + for i = 1, #str do + local v = str:byte(i) + l[#l+1] = NUMBER_TO_HEX[math.floor(v / 16)] + l[#l+1] = NUMBER_TO_HEX[v % 16] + l[#l+1] = ' ' + end + l[#l] = nil + return table.concat(l, '') +end + +local function is_nice_ascii_string (str) + for i = 1, #str do + local byte = str:byte(i) + if not (32 <= byte and byte <= 126) then return false end + end + return true +end + +local function get_type_and_size_of_singular ( ctype ) + local nr_elements = 1 + while true do + local etype, elements = ctype:match('(.+)%[(%d*)%]$') + if not elements then break end + ctype, nr_elements = etype, nr_elements * elements + end + return ctype, nr_elements +end + +-------------------------------------------------------------------------------- + +local CDATA_REPR_MATCHER = 'cdata<(.+)>: (0x%w+)' + +return function (value, options, depth, l) + local native_repr = tostring(value) + local data_length = ffi.sizeof(value) + local ctype, addr = native_repr:match(CDATA_REPR_MATCHER) + + l[#l+1] = 'cdata {' + --l[#l+1] = '\n\tnative = \'' .. native_repr .. '\',' + l[#l+1] = '\n\ttype = ' .. ctype .. ',' + l[#l+1] = '\n\taddr = ' .. addr .. ',' + if data_length then + -- Size + local str = ffi.string(value, data_length) + l[#l+1] = '\n\tsize = ' .. data_length .. ',' + + -- Element size and type + local element_type, nr_elements = get_type_and_size_of_singular(ctype) + local element_size = data_length / nr_elements + l[#l+1] = '\n\tnr_e = ' .. nr_elements .. ',' + l[#l+1] = '\n\ttype_e = ' .. element_type .. ',' + l[#l+1] = '\n\tsize_e = ' .. element_size .. ',' + + -- + if is_nice_ascii_string(str) then + l[#l+1] = '\n\tstr = ' .. str .. ',' + end + l[#l+1] = '\n\tbin = ' .. to_hex(str) .. ',' + + + + + end + l[#l+1] = '\n}' +end diff --git a/pretty.lua b/pretty.lua index 8653637..19d6824 100644 --- a/pretty.lua +++ b/pretty.lua @@ -9,6 +9,7 @@ do -- Load number and function formatting format_number = select(2, pcall(require, thispath..'number')) format_function = select(2, pcall(require, thispath..'function')) + format_cdata = select(2, pcall(require, thispath..'cdata')) -- Load other stuff local was_loaded @@ -480,6 +481,11 @@ if not format_function then end end +if not format_cdata then + -- Very simple cdata formatting, if cdata.lua is not available. + format_cdata = format_primitive +end + local TYPE_TO_FORMAT_FUNC = { ['nil'] = format_primitive, ['boolean'] = format_primitive, @@ -491,7 +497,7 @@ local TYPE_TO_FORMAT_FUNC = { -- TODO ['function'] = format_function, ['userdata'] = format_primitive, - ['cdata'] = format_primitive, -- Luajit exclusive ? + ['cdata'] = format_cdata, -- Luajit exclusive ? } function format_value (value, _, depth, l) diff --git a/test/test_pretty.lua b/test/test_pretty.lua index 7bf2bd6..87968bc 100644 --- a/test/test_pretty.lua +++ b/test/test_pretty.lua @@ -377,15 +377,35 @@ if type(jit) == 'table' then format_test { input = ffi.C.poll, - approx = true, expect = 'cdata<.+>: 0x%x+', } - format_test { - input = ffi.new('int[10]'), - approx = true, - expect = 'cdata<.+>: 0x%x+', - } + do + local list = ffi.new('char [17]') + for i = 0, 16 do list[i] = i end + format_test { + input = list, + expect = 'cdata<.+>: 0x%x+', + } + end + + do + local list = ffi.new('char [10]') + for i = 0, 10-1 do list[i] = i + 65 end + format_test { + input = list, + expect = 'cdata<.+>: 0x%x+', + } + end + + do + local mat = ffi.new('char [3][3]') + for x = 0, 2 do for y = 0, 2 do mat[x][y] = x * 16 + y end end + format_test { + input = mat, + expect = 'cdata<.+>: 0x%x+', + } + end end --------------------------------------------------------------------------------