-
Notifications
You must be signed in to change notification settings - Fork 3
/
ffi-combine.lua
158 lines (128 loc) · 4.17 KB
/
ffi-combine.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
local headerBegin = "--[["
local headerEnd = "--]]"
local ffiBlockBegin = "ffi.cdef[["
local ffiBlockEnd = "]]"
local sourceListPlaceHolder = "<source%-files>"
-- a hyphen is a special character so it must be preceded by "%" escape character
local outputOption = "--output="
local outputFileName = "out.lua" -- default output file name
local headerOption = "--header="
local headerFileName = ""
local footerOption = "--footer="
local footerFileName = ""
local inputFiles = {} -- list of files to combine
local bindings = {} -- map of bindings
local output = {} -- list of lines to write to the output file
local sourceFiles = {} -- list of source files that given lua files are based on
local sourcesLineIndex = -1
-- this function determines whether the specified table contains the given element
function table.contains(table, element)
for _, value in pairs(table) do
if value == element then
return true
end
end
return false
end
-- get names of the lua files to combine (and if set, output, header and footer file names)
for i = 1, #arg do
if string.sub(arg[i], 1, string.len(outputOption)) == outputOption then
outputFileName = string.sub(arg[i], string.len(outputOption) + 1)
elseif string.sub(arg[i], 1, string.len(headerOption)) == headerOption then
headerFileName = string.sub(arg[i], string.len(headerOption) + 1)
elseif string.sub(arg[i], 1, string.len(footerOption)) == footerOption then
footerFileName = string.sub(arg[i], string.len(footerOption) + 1)
else
table.insert(inputFiles, arg[i])
end
end
if headerFileName ~= "" then
local headerFile = io.open(headerFileName, "r")
if not headerFile then
error("File: " .. headerFileName .. " does not exist.")
end
io.close(headerFile)
for line in io.lines(headerFileName) do
if string.find(line, sourceListPlaceHolder) then
-- line containing "<source-files>" token is not copied to the output
-- it serves as an indicator of where list of source files should be inserted
sourcesLineIndex = #output
else
-- other lines in the header are copied to the output
table.insert(output, line .. "\n")
end
end
end
table.insert(output, "ffi = require(\"ffi\")\nffi.cdef[[")
for _, fileName in ipairs(inputFiles) do
local inputFile = io.open(fileName , "r")
if not inputFile then
error("File: " .. fileName .. " does not exist.")
end
io.close(inputFile)
local isStartBlock = true
local isEndBlock = false
local isInHeader = false
local currentBinding = ""
for line in io.lines(fileName) do
if line == headerBegin then
isInHeader = true
end
if isInHeader then
if string.find(line, ">> ") then
if not table.contains(sourceFiles, line) then
table.insert(sourceFiles, line)
end
end
end
if line == ffiBlockEnd then
isEndBlock = true
end
if not isStartBlock and not isEndBlock then
if not line or line == "" then
if (currentBinding ~= "") then
if not bindings[currentBinding] then
table.insert(output, "\n")
table.insert(output, currentBinding)
bindings[currentBinding] = currentBinding
end
end
currentBinding = ""
else
currentBinding = currentBinding .. "\n" .. line
end
end
if line == ffiBlockBegin then
isStartBlock = false
end
if line == headerEnd then
isInHeader = false
end
end
end
if sourcesLineIndex ~= -1 then
-- insert list of source files (each in new line)
for i, sourceFileName in ipairs(sourceFiles) do
table.insert(output, sourcesLineIndex + i, sourceFileName .. "\n")
end
end
table.insert(output, "\n\n]]\n")
if footerFileName ~= "" then
local footerFile = io.open(footerFileName, "r")
if not footerFile then
error("File: " .. footerFileName .. " does not exist.")
end
io.close(footerFile)
for line in io.lines(footerFileName) do
table.insert(output, line .. "\n")
end
end
-- write output to a file
local outFile = io.open(outputFileName , "w")
if not outFile then
error("Cannot write to file: " .. outputFileName)
end
for _, outputLine in ipairs(output) do
outFile:write(outputLine)
end
io.close(outFile)