You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
245 lines
7.0 KiB
Lua
245 lines
7.0 KiB
Lua
#!/usr/bin/env luajit
|
|
|
|
local arg = arg
|
|
|
|
local string = require("string")
|
|
local io = require("io")
|
|
local os = require("os")
|
|
local table = require("table")
|
|
|
|
local cl = require("ljclang")
|
|
|
|
local format = string.format
|
|
local print = print
|
|
|
|
----------
|
|
|
|
local function printf(fmt, ...)
|
|
print(format(fmt, ...))
|
|
end
|
|
|
|
local function errprintf(fmt, ...)
|
|
io.stderr:write(format(fmt, ...).."\n")
|
|
end
|
|
|
|
local function usage(hline)
|
|
if (hline) then
|
|
print(hline)
|
|
end
|
|
print("Usage: "..arg[0].." [our_options...] <file.h> [clang_options...]")
|
|
print " -p <filterPattern>"
|
|
print " -x <excludePattern1> [-x <excludePattern2>] ..."
|
|
print " -s <stripPattern>"
|
|
print " -1 <string to print before everything>"
|
|
print " -2 <string to print after everything>"
|
|
print " -C: print lines like"
|
|
print " static const int membname = 123; (enums/macros only)"
|
|
print " -R: reverse mapping, only if one-to-one. Print lines like"
|
|
print " [123] = \"membname\"; (enums/macros only)"
|
|
print " -f <formatFunc>: user-provided body for formatting function (enums/macros only)"
|
|
print " Accepts args `k', `v'; `f' is string.format. Must return a formatted line."
|
|
print[[ Example: "return f('%s = %s%s,', k, k:find('KEY_') and '65536+' or '', v)"]]
|
|
print " Incompatible with -C or -R."
|
|
print " -Q: be quiet"
|
|
print " -w: extract what? Can be"
|
|
print " EnumConstantDecl (default), TypedefDecl, FunctionDecl, MacroDefinition"
|
|
os.exit(1)
|
|
end
|
|
|
|
local parsecmdline = require("parsecmdline_pk")
|
|
|
|
-- Meta-information about options, see parsecmdline_pk.
|
|
local opt_meta = { p=true, x=1, s=true, C=false, R=false, Q=false,
|
|
['1']=true, ['2']=true, w=true, f=true }
|
|
|
|
local opts, args = parsecmdline.getopts(opt_meta, arg, usage)
|
|
|
|
local pat = opts.p
|
|
local xpats = opts.x
|
|
local spat = opts.s
|
|
local constint = opts.C
|
|
local reverse = opts.R
|
|
local quiet = opts.Q
|
|
local what = opts.w or "EnumConstantDecl"
|
|
local fmtfuncCode = opts.f
|
|
|
|
local extractEnum = (what == "EnumConstantDecl")
|
|
local extractMacro = (what:find("^Macro"))
|
|
|
|
local printbefore = opts['1']
|
|
local printafter = opts['2']
|
|
|
|
if (#args == 0) then
|
|
usage()
|
|
end
|
|
|
|
if (not (extractEnum or extractMacro) and (constint or reverse)) then
|
|
usage("Options -C and -R only available for enum or macro extraction")
|
|
end
|
|
|
|
local fmtfunc
|
|
if (fmtfuncCode) then
|
|
if (not (extractEnum or extractMacro)) then
|
|
usage("Option -f only available for enum or macro extraction")
|
|
end
|
|
|
|
if (constint or reverse) then
|
|
usage("Option -f is incompatible with -C or -R")
|
|
end
|
|
|
|
local func, errmsg = loadstring([[
|
|
local f=string.format
|
|
return function(k, v)
|
|
]]..fmtfuncCode..[[
|
|
end
|
|
]])
|
|
if (func == nil) then
|
|
io.stderr:write("Error loading string: "..errmsg.."\n")
|
|
os.exit(1)
|
|
end
|
|
|
|
fmtfunc = func()
|
|
end
|
|
|
|
local opts = extractMacro and {"DetailedPreprocessingRecord"} or nil
|
|
|
|
local filename = args[1]
|
|
do
|
|
local f, msg = io.open(filename)
|
|
if (f == nil) then
|
|
errprintf("ERROR: Failed opening %s", msg)
|
|
os.exit(1)
|
|
end
|
|
f:close()
|
|
end
|
|
|
|
local index = cl.createIndex(true, false)
|
|
local tu = index:parse("", args, opts)
|
|
if (tu == nil) then
|
|
errprintf("ERROR: Failed parsing %s", filename)
|
|
os.exit(1)
|
|
end
|
|
|
|
if (not quiet) then
|
|
local diags = tu:diagnostics()
|
|
for i=1,#diags do
|
|
local d = diags[i]
|
|
io.stderr:write(d.text.."\n")
|
|
end
|
|
end
|
|
|
|
-- Mapping of enum value to its name for -R.
|
|
local enumname = {}
|
|
-- Mapping of running index to enum value for -R.
|
|
local enumseq = {}
|
|
|
|
local V = cl.ChildVisitResult
|
|
|
|
local function checkexclude(name)
|
|
for i=1,#xpats do
|
|
if (name:find(xpats[i])) then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Get definition string of #define macro definition cursor.
|
|
local function getDefStr(cur)
|
|
local tokens = cur:_tokens()
|
|
-- TOKENIZE_WORKAROUND
|
|
-- print("tokens: ["..table.concat(tokens, "|", 2, #tokens).."]")
|
|
if (#tokens >= 3) then
|
|
tokens[#tokens] = nil
|
|
end
|
|
return table.concat(tokens, " ", 2, #tokens)
|
|
end
|
|
|
|
local visitor = cl.regCursorVisitor(
|
|
function(cur, parent)
|
|
if (extractEnum) then
|
|
if (cur:haskind("EnumDecl")) then
|
|
return V.Recurse
|
|
end
|
|
end
|
|
|
|
if (cur:haskind(what)) then
|
|
local name = cur:displayName()
|
|
|
|
if (pat == nil or name:find(pat)) then
|
|
local exclude = false
|
|
|
|
if (not checkexclude(name)) then
|
|
local ourname = spat and name:gsub(spat, "") or name
|
|
|
|
if (extractEnum or extractMacro) then
|
|
-- Enumeration constants
|
|
local val = extractEnum and cur:enumval() or getDefStr(cur)
|
|
|
|
-- NOTE: tonumber(val) == nil can only happen with #defines that are not
|
|
-- like a literal number.
|
|
if (not extractMacro or tonumber(val) ~= nil) then
|
|
if (fmtfunc) then
|
|
print(fmtfunc(ourname, val))
|
|
elseif (reverse) then
|
|
if (enumname[val]) then
|
|
printf("Error: enumeration value %d not unique: %s and %s",
|
|
val, enumname[val], ourname)
|
|
os.exit(2)
|
|
end
|
|
enumname[val] = ourname
|
|
enumseq[#enumseq+1] = val
|
|
elseif (constint) then
|
|
printf("static const int %s = %s;", ourname, val)
|
|
else
|
|
printf("%s = %s,", ourname, val)
|
|
end
|
|
end
|
|
elseif (what=="FunctionDecl") then
|
|
-- Function declaration
|
|
local rettype = cur:resultType()
|
|
if (not checkexclude(rettype:name())) then
|
|
printf("%s %s;", rettype, ourname)
|
|
end
|
|
elseif (what=="TypedefDecl") then
|
|
-- Type definition
|
|
local utype = cur:typedefType()
|
|
if (not checkexclude(utype:name())) then
|
|
printf("typedef %s %s;", utype, ourname)
|
|
end
|
|
--[[
|
|
elseif (extractMacro) then
|
|
local fn, linebeg, lineend = cur:location(true)
|
|
local defstr = getDefStr(cur)
|
|
|
|
printf("%s @ %s:%d%s :: %s", ourname, fn, linebeg,
|
|
(lineend~=linebeg) and "--"..lineend or "", defstr)
|
|
--]]
|
|
else
|
|
-- Anything else
|
|
printf("%s", ourname)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return V.Continue
|
|
end)
|
|
|
|
if (printbefore) then
|
|
print(printbefore)
|
|
end
|
|
|
|
tu:cursor():children(visitor)
|
|
|
|
if (reverse) then
|
|
for i=1,#enumseq do
|
|
local val = enumseq[i]
|
|
local name = enumname[val]
|
|
printf("[%d] = %q;", val, name)
|
|
end
|
|
end
|
|
|
|
if (printafter) then
|
|
print(printafter)
|
|
end
|