17
17
-- 2008-02-24 split into multiple files
20
-- BitOp, see http://bitop.luajit.org/
23
-- The binding to the hash functions used in this package. Compiled during
22
32
-- add the directory where this Lua file is in to the package search path.
23
33
package.path = package.path .. ";" .. string.gsub(arg[0], "%/[^/]+$", "/?.lua")
28
35
xml = require "xml-parser"
29
36
typedefs = xml.typedefs
30
37
types = require "xml-types"
31
38
output = require "xml-output"
33
41
typedefs_sorted = {}
34
42
typedefs_name2id = {}
36
architecture = nil -- target architecture
37
free_methods = {} -- [name] = 0/1
39
parse_errors = 0 -- count errors
43
config = {} -- configuration of architecture, module etc.
44
parse_errors = 0 -- count errors (used in xml-parser.lua)
40
45
verbose = 0 -- verbosity level
46
good_files = {} -- [file_id] = true for "interesting" include files
48
non_native_includes = {} -- [path] = libname
53
-- Print an error message and increase the error counter.
54
function err(fmt, ...)
55
if select('#', ...) > 0 then
56
fmt = string.format(fmt, ...)
59
build_errors = build_errors + 1
43
63
-- Unfortunately, sometimes ENUM fields in structures are not declared as such,
90
117
-- The structures named *Iface are required to be able to override interface
118
-- virtual functions. They are not intended to be used directly by the user,
119
-- and therefore don't show up as function arguments.
120
-- All of these structures are named _*Iface, and have a typedef with
121
-- *Iface for them. Actually, we need a pointer to that, which isn't defined.
92
123
function mark_ifaces_as_used()
93
125
for type_id, t in pairs(typedefs) do
94
if t.type == "struct" and string.match(t.name, "Iface$") then
95
types.mark_type_id_in_use(type_id)
126
if t.type == "typedef" and string.match(t.name, "Iface$")
127
and good_files[t.file_id] then
128
-- types.mark_type_id_in_use(type_id)
129
name2id[t.name] = type_id
130
synthesize_type(t.name .. "*", name2id)
137
-- Read all config files for the libraries in the current setup. Note
138
-- that this usually is just one, and probably never is more than one.
140
function load_lib_config()
144
cfg_file = string.format("%s/spec.lua", config.srcdir)
145
config.lib = load_spec(cfg_file)
147
if config.lib.native_types then
148
for k, v in pairs(config.lib.native_types) do
149
config.native_types[k] = v
155
-- Read all spec files of other modules and extract the include_dirs. This
156
-- is used to store for non-native types which module should handle it.
158
function load_other_lib_config()
161
for libname in lfs.dir("src") do
162
ifile = "src/" .. libname .. "/spec.lua"
163
if string.sub(libname, 1, 1) ~= "."
164
and lfs.attributes(ifile, "mode") == "file" then
165
cfg = load_spec(ifile, true)
166
for _, path in ipairs(cfg.include_dirs or {}) do
167
non_native_includes[path] = libname
174
-- Make a table listing all include paths of the current module.
175
function _get_include_paths()
177
for _, path in ipairs(config.lib.include_dirs or {}) do
178
tbl[#tbl + 1] = "/" .. path .. "/"
185
-- Look at all the file IDs and mark those files that are relevant for the
188
function make_file_list()
189
local paths = _get_include_paths()
190
good_files = {} -- [id] = true
192
for id, name in pairs(xml.filelist) do
193
for i, path in ipairs(paths) do
194
if string.find(name, path, 1, true) then
195
good_files[id] = true
105
204
-- Take a look at all relevant functions and the data types they reference.
205
-- Mark all these data types as used. Note that functions prototypes that only
206
-- appear in structures (i.e., function pointers) are not considered here.
208
-- Note that this does not consider function types, which are only to be
209
-- found in the typedefs list.
108
211
function analyze_functions()
109
local inc_prefixes = {
110
g=true, gdk=true, -- for glib, gdk
113
pango=true, -- for pango
114
cairo=true, -- for cairo
115
html=true, css=true, dom=true, -- for libgtkhtml-2.0
118
-- Make a sorted list of functions to output. Only use function with
119
-- one of the prefixes in the inc_prefixes list.
213
-- Make a sorted list of functions to output. Only use functions declared
214
-- in one of the "good" files, and ignore those starting with "_", which
215
-- are most likely private. v[1][3] contains the file's ID.
120
216
for k, v in pairs(xml.funclist) do
122
if pos ~= nil and inc_prefixes[k:sub(1, pos - 1)] then
219
if good_files[v[1][3]] and string.sub(k, 1, 1) ~= "_" then
123
220
function_list[#function_list + 1] = k
124
221
_function_analyze(k)
225
-- If aliases are defined, add them too. The "from" function must
226
-- exist, while the "to" function must not exist. Note that the "from"
227
-- function remains available, and must remain, because the argument
228
-- list is defined there and not in the alias function entry.
229
if config.lib.aliases then
230
for to, from in pairs(config.lib.aliases) do
231
assert(xml.funclist[from])
232
assert(not xml.funclist[to])
233
function_list[#function_list + 1] = to
234
xml.funclist[to] = from
235
_function_analyze(from)
127
239
table.sort(function_list)
163
270
-- in_use: directly used; marked: indirectly used
164
271
if t.in_use or t.marked then
165
272
_analyze_struct(id, t)
167
-- print("SKIP", t.name)
279
-- After finding all "native" types, those that refer to them are also
282
function analyze_structs_native()
283
for id, t in pairs(typedefs) do
291
-- Given a type ID, check whether that type is native, or a fundamental type.
294
-- @return false=not native, 1=native, 2=fundamental
296
function _is_native(t)
297
if t.is_native ~= nil then return t.is_native end
300
if t.type == 'fundamental' then
302
elseif good_files[t.file_id] then
304
elseif config.native_types[t.full_name] then
307
-- follow pointers and qualifiers, then check that type.
309
while t2.type == 'pointer' or t2.type == 'qualifier' do
310
t2 = typedefs[t2.what]
312
if t2.type == 'fundamental' then
314
elseif t2.type == 'func' then
321
t.is_native = is_native
326
-- For each member of the structure, mark their type in use.
173
327
function _analyze_struct(id, t)
174
328
local st = t.struct
175
329
local ignorelist = { constructor=true, union=true, struct=true }
178
331
for _, member_name in ipairs(st.members) do
179
332
member = st.fields[member_name]
180
333
if member and not ignorelist[member.type] then
181
-- tp = types.resolve_type(member.type, member.size)
183
334
types.mark_type_id_in_use(member.type,
184
335
string.format("%s.%s", t.name, member.name or member_name))
243
394
-- Try to synthetize a new pointer type for still undefined types.
244
395
for full_name, v in pairs(ar) do
245
396
if not synthesize_type(full_name, name2id) then
246
print("Can't synthesize type for " .. full_name)
397
err("Type in include_types can't be synthesized: %s", full_name)
248
399
ar[full_name] = nil
252
-- what's left hasn't been found.
253
for full_name, v in pairs(ar) do
254
print("OVERRIDE NOT FOUND", full_name)
405
local next_synth_nr = 1
408
-- The requested type doesn't exist, so try to create it by deriving a new
409
-- type from an existing type. This includes removing "const" and
262
412
function synthesize_type(full_name, name2id)
413
local parent_name, parent_id, new_id, parent, t, new_item
264
if string.sub(full_name, -1) ~= "*" then
415
if string.sub(full_name, 1, 6) == "const " then
416
parent_name = string.sub(full_name, 7)
417
new_item = { type="qualifier", const=true }
418
elseif string.sub(full_name, -1) == "*" then
419
parent_name = string.sub(full_name, 1, -2)
420
new_item = { type="pointer" }
268
local parent_name = string.sub(full_name, 1, -2)
269
local parent_id = name2id[parent_name] or synthesize_type(parent_name,
425
parent_id = name2id[parent_name] or synthesize_type(parent_name, name2id)
271
426
if not parent_id then return false end
273
local new_id = "synth" .. next_synth_nr
428
new_id = "synth" .. next_synth_nr
274
429
next_synth_nr = next_synth_nr + 1
275
local parent = typedefs[parent_id]
276
typedefs[new_id] = { type="pointer", what=parent_id, name=parent.name }
277
local t = types.mark_type_id_in_use(new_id, nil)
430
parent = typedefs[parent_id]
432
new_item.what = parent_id
433
new_item.is_native = parent.is_native
434
typedefs[new_id] = new_item
436
t = types.mark_type_id_in_use(new_id, nil)
278
437
if verbose > 1 then
279
print("mark override new", new_id, t.type, t.full_name)
438
print("mark override new", new_id, t.type, t.full_name, full_name)
288
function _handle_char_ptr_returns(arg_list, tp, fname)
292
-- this is what the API says; consts should not be freed.
293
local default_method = tp.const and 0 or 1
295
-- The free_method may have been defined by reading the
296
-- char_ptr_handling.txt file.
297
if arg_list.free_method then
298
method = arg_list.free_method
301
-- This might be a function argument or structure member, and therefore
302
-- should have an entry in this table:
303
method = free_methods[fname]
306
print(string.format("Warning: free method not defined for %s",
308
method = default_method
312
-- Warn if API and my list differ. Sometimes this is intentionally,
313
-- but then should be documented in char_ptr_handling.txt.
314
if method ~= default_method then
315
print("Warning: inconsistency of free method of function " .. fname)
318
return tp.fid + method
325
function get_extra_data()
327
local arch, arch2, func, method, inverse
329
for line in io.lines("src/char_ptr_handling.txt") do
331
arch = string.match(line, "^arch (.*)$")
333
arch2 = string.match(arch, "^not (.*)$")
339
active = arch == "all" and true or string.match(architecture, arch)
340
if inverse then active = not active end
343
if not arch and active then
344
func, method = string.match(line, '^([^#,]*),(%d)$')
345
if func and method then
346
_set_char_ptr_handling(func, tonumber(method))
354
function _set_char_ptr_handling(funcname, method)
356
-- funcnames that include a dot are not simple functions, but refer to
357
-- an argument of a function, or a member of a structure.
358
local parent, item = string.match(funcname, "^([^.]+)%.(.*)$")
359
if parent and item then
360
free_methods[parent == "funcptr" and item or funcname] = method
364
local fi = xml.funclist[funcname]
366
print("Warning: undefined function in char_ptr_handling: " .. funcname)
370
assert(fi.free_method == nil, "Duplicate in char_ptr_handling.txt: "
372
tp = types.resolve_type(fi[1][1])
374
-- must be a char*, i.e. with one level of indirection
375
assert(tp.fname == "char")
376
assert(tp.pointer == 1)
378
-- If a return type is "const char*", then this usually means "do not
379
-- free it". Alas, this rule of thumb has exceptions.
380
if not (method == 0 and tp.const or method == 1 and not tp.const) then
381
print("Warning: inconsistency of free method of function " .. funcname)
384
fi.free_method = method
392
446
-- Certain #defines from the Gtk/Gdk include files are relevant, but not
393
447
-- included in types.xml. Extract them and add them to the ENUM list.
449
-- @param fname Full pathname of the file to read
450
-- @param nums boolean - whether to extract numerical #defines
395
452
function parse_header_file(fname, nums)
397
454
local name, value
484
560
-- remaining must be three --
485
561
if #arg ~= 3 then
486
print(string.format("Usage: %s [options] {outputdir} {xmlfile} {arch}",
562
print(string.format("Usage: %s [options] {outputdir} {xmlfile} {cfgfile}",
491
architecture = arg[3]
567
-- read config file for this build
568
config = load_config(arg[3])
569
assert(config.arch, "No architecture defined in config file")
570
config.arch = string.lower(config.arch)
571
config.arch_os = string.match(config.arch, "^[^-]+")
572
config.native_types = {}
574
logfile = assert(io.open(arg[1] .. "/parse-xml.log", "w"))
576
-- read config file for the library in this module
578
load_other_lib_config()
493
580
-- read the XML data
494
581
xml.parse_xml(arg[2])
497
584
mark_ifaces_as_used()
498
585
analyze_globals()
500
586
analyze_functions()
502
588
analyze_structs()
503
589
mark_all_enums_as_used()
590
analyze_structs_native()
504
591
promote_enum_typedefs()
506
593
-- before writing the structures, the functions must be looked at to
507
594
-- find prototypes that need registering.
509
types.assign_type_idx()
596
typedefs_sorted = types.assign_type_idx()
511
598
-- Now that all used types have their IDs, the function prototypes
512
599
-- can be registered.
513
600
types.register_function_prototypes()
515
path_gtk = "/usr/include/gtk-2.0"
516
path_glib = "/usr/include/glib-2.0"
517
parse_header_file(path_gtk .. "/gtk/gtkstock.h", false)
518
parse_header_file(path_glib .. "/gobject/gtype.h", false)
519
parse_header_file(path_gtk .. "/gdk/gdkkeysyms.h", true)
521
output.output_types(arg[1] .. "/gtkdata.structs.c")
522
output.output_enums(arg[1] .. "/gtkdata.enums.txt")
523
output.output_functions(arg[1] .. "/gtkdata.funcs.txt")
524
output.output_fundamental_types(arg[1] .. "/gtkdata.types.c")
525
output.output_globals(arg[1] .. "/gtkdata.globals.c")
527
print("\n --- " ..arg[2] .. " Parsing Results ---\n")
528
xml.show_statistics()
529
types.show_statistics()
530
output.show_statistics()
604
-- The core library must provide support for all fundamental types, even though
605
-- it doesn't use all of them. The modules don't have type handling, just
606
-- have a list of names of fundamental types they use.
607
if config.is_core then
608
types.register_all_fundamental_types()
611
if build_errors > 0 then
616
output.output_types(arg[1] .. "/types.c")
617
output.output_constants(arg[1] .. "/constants.txt")
618
output.output_functions(arg[1] .. "/functions.txt")
619
if config.is_core then
620
output.output_fundamental_types(arg[1] .. "/fundamentals.c")
622
output.output_fundamental_hash(arg[1] .. "/fundamentals.c")
624
output.output_globals(arg[1] .. "/globals.c")
625
output.output_code(arg[1] .. "/generated.c")
626
write_summary(arg[1] .. "/parse.log")
629
for k, t in pairs(typedefs) do
630
if not t.in_use and not t.marked and good_files[t.file_id] then
631
print("unused", k, t.type, t.name)