diff options
| author | Mike Pall <mike> | 2012-06-08 20:54:47 +0200 |
|---|---|---|
| committer | Mike Pall <mike> | 2012-06-08 21:14:33 +0200 |
| commit | cccf7638989275e57377e2e25595213caacb7da3 (patch) | |
| tree | 40aa697533f22adbd3cbef8f36148abb29ec0de1 /lib/bcsave.lua | |
| parent | 7266e27404caf007e3ff3fc4e204ea6d4c6a4670 (diff) | |
| download | luajit-cccf7638989275e57377e2e25595213caacb7da3.tar.gz luajit-cccf7638989275e57377e2e25595213caacb7da3.tar.bz2 luajit-cccf7638989275e57377e2e25595213caacb7da3.zip | |
Move lib/* to src/jit/*.
Diffstat (limited to 'lib/bcsave.lua')
| -rw-r--r-- | lib/bcsave.lua | 500 |
1 files changed, 0 insertions, 500 deletions
diff --git a/lib/bcsave.lua b/lib/bcsave.lua deleted file mode 100644 index 70cb6925..00000000 --- a/lib/bcsave.lua +++ /dev/null | |||
| @@ -1,500 +0,0 @@ | |||
| 1 | ---------------------------------------------------------------------------- | ||
| 2 | -- LuaJIT module to save/list bytecode. | ||
| 3 | -- | ||
| 4 | -- Copyright (C) 2005-2012 Mike Pall. All rights reserved. | ||
| 5 | -- Released under the MIT license. See Copyright Notice in luajit.h | ||
| 6 | ---------------------------------------------------------------------------- | ||
| 7 | -- | ||
| 8 | -- This module saves or lists the bytecode for an input file. | ||
| 9 | -- It's run by the -b command line option. | ||
| 10 | -- | ||
| 11 | ------------------------------------------------------------------------------ | ||
| 12 | |||
| 13 | local jit = require("jit") | ||
| 14 | assert(jit.version_num == 20000, "LuaJIT core/library version mismatch") | ||
| 15 | |||
| 16 | -- Symbol name prefix for LuaJIT bytecode. | ||
| 17 | local LJBC_PREFIX = "luaJIT_BC_" | ||
| 18 | |||
| 19 | ------------------------------------------------------------------------------ | ||
| 20 | |||
| 21 | local function usage() | ||
| 22 | io.stderr:write[[ | ||
| 23 | Save LuaJIT bytecode: luajit -b[options] input output | ||
| 24 | -l Only list bytecode. | ||
| 25 | -s Strip debug info (default). | ||
| 26 | -g Keep debug info. | ||
| 27 | -n name Set module name (default: auto-detect from input name). | ||
| 28 | -t type Set output file type (default: auto-detect from output name). | ||
| 29 | -a arch Override architecture for object files (default: native). | ||
| 30 | -o os Override OS for object files (default: native). | ||
| 31 | -e chunk Use chunk string as input. | ||
| 32 | -- Stop handling options. | ||
| 33 | - Use stdin as input and/or stdout as output. | ||
| 34 | |||
| 35 | File types: c h obj o raw (default) | ||
| 36 | ]] | ||
| 37 | os.exit(1) | ||
| 38 | end | ||
| 39 | |||
| 40 | local function check(ok, ...) | ||
| 41 | if ok then return ok, ... end | ||
| 42 | io.stderr:write("luajit: ", ...) | ||
| 43 | io.stderr:write("\n") | ||
| 44 | os.exit(1) | ||
| 45 | end | ||
| 46 | |||
| 47 | local function readfile(input) | ||
| 48 | if type(input) == "function" then return input end | ||
| 49 | if input == "-" then input = nil end | ||
| 50 | return check(loadfile(input)) | ||
| 51 | end | ||
| 52 | |||
| 53 | local function savefile(name, mode) | ||
| 54 | if name == "-" then return io.stdout end | ||
| 55 | return check(io.open(name, mode)) | ||
| 56 | end | ||
| 57 | |||
| 58 | ------------------------------------------------------------------------------ | ||
| 59 | |||
| 60 | local map_type = { | ||
| 61 | raw = "raw", c = "c", h = "h", o = "obj", obj = "obj", | ||
| 62 | } | ||
| 63 | |||
| 64 | local map_arch = { | ||
| 65 | x86 = true, x64 = true, arm = true, ppc = true, ppcspe = true, | ||
| 66 | mips = true, mipsel = true, | ||
| 67 | } | ||
| 68 | |||
| 69 | local map_os = { | ||
| 70 | linux = true, windows = true, osx = true, freebsd = true, netbsd = true, | ||
| 71 | openbsd = true, solaris = true, | ||
| 72 | } | ||
| 73 | |||
| 74 | local function checkarg(str, map, err) | ||
| 75 | str = string.lower(str) | ||
| 76 | local s = check(map[str], "unknown ", err) | ||
| 77 | return s == true and str or s | ||
| 78 | end | ||
| 79 | |||
| 80 | local function detecttype(str) | ||
| 81 | local ext = string.match(string.lower(str), "%.(%a+)$") | ||
| 82 | return map_type[ext] or "raw" | ||
| 83 | end | ||
| 84 | |||
| 85 | local function checkmodname(str) | ||
| 86 | check(string.match(str, "^[%w_.%-]+$"), "bad module name") | ||
| 87 | return string.gsub(str, "[%.%-]", "_") | ||
| 88 | end | ||
| 89 | |||
| 90 | local function detectmodname(str) | ||
| 91 | if type(str) == "string" then | ||
| 92 | local tail = string.match(str, "[^/\\]+$") | ||
| 93 | if tail then str = tail end | ||
| 94 | local head = string.match(str, "^(.*)%.[^.]*$") | ||
| 95 | if head then str = head end | ||
| 96 | str = string.match(str, "^[%w_.%-]+") | ||
| 97 | else | ||
| 98 | str = nil | ||
| 99 | end | ||
| 100 | check(str, "cannot derive module name, use -n name") | ||
| 101 | return string.gsub(str, "[%.%-]", "_") | ||
| 102 | end | ||
| 103 | |||
| 104 | ------------------------------------------------------------------------------ | ||
| 105 | |||
| 106 | local function bcsave_tail(fp, output, s) | ||
| 107 | local ok, err = fp:write(s) | ||
| 108 | if ok and output ~= "-" then ok, err = fp:close() end | ||
| 109 | check(ok, "cannot write ", output, ": ", err) | ||
| 110 | end | ||
| 111 | |||
| 112 | local function bcsave_raw(output, s) | ||
| 113 | local fp = savefile(output, "wb") | ||
| 114 | bcsave_tail(fp, output, s) | ||
| 115 | end | ||
| 116 | |||
| 117 | local function bcsave_c(ctx, output, s) | ||
| 118 | local fp = savefile(output, "w") | ||
| 119 | if ctx.type == "c" then | ||
| 120 | fp:write(string.format([[ | ||
| 121 | #ifdef _cplusplus | ||
| 122 | extern "C" | ||
| 123 | #endif | ||
| 124 | #ifdef _WIN32 | ||
| 125 | __declspec(dllexport) | ||
| 126 | #endif | ||
| 127 | const char %s%s[] = { | ||
| 128 | ]], LJBC_PREFIX, ctx.modname)) | ||
| 129 | else | ||
| 130 | fp:write(string.format([[ | ||
| 131 | #define %s%s_SIZE %d | ||
| 132 | static const char %s%s[] = { | ||
| 133 | ]], LJBC_PREFIX, ctx.modname, #s, LJBC_PREFIX, ctx.modname)) | ||
| 134 | end | ||
| 135 | local t, n, m = {}, 0, 0 | ||
| 136 | for i=1,#s do | ||
| 137 | local b = tostring(string.byte(s, i)) | ||
| 138 | m = m + #b + 1 | ||
| 139 | if m > 78 then | ||
| 140 | fp:write(table.concat(t, ",", 1, n), ",\n") | ||
| 141 | n, m = 0, #b + 1 | ||
| 142 | end | ||
| 143 | n = n + 1 | ||
| 144 | t[n] = b | ||
| 145 | end | ||
| 146 | bcsave_tail(fp, output, table.concat(t, ",", 1, n).."\n};\n") | ||
| 147 | end | ||
| 148 | |||
| 149 | local function bcsave_elfobj(ctx, output, s, ffi) | ||
| 150 | ffi.cdef[[ | ||
| 151 | typedef struct { | ||
| 152 | uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7]; | ||
| 153 | uint16_t type, machine; | ||
| 154 | uint32_t version; | ||
| 155 | uint32_t entry, phofs, shofs; | ||
| 156 | uint32_t flags; | ||
| 157 | uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx; | ||
| 158 | } ELF32header; | ||
| 159 | typedef struct { | ||
| 160 | uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7]; | ||
| 161 | uint16_t type, machine; | ||
| 162 | uint32_t version; | ||
| 163 | uint64_t entry, phofs, shofs; | ||
| 164 | uint32_t flags; | ||
| 165 | uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx; | ||
| 166 | } ELF64header; | ||
| 167 | typedef struct { | ||
| 168 | uint32_t name, type, flags, addr, ofs, size, link, info, align, entsize; | ||
| 169 | } ELF32sectheader; | ||
| 170 | typedef struct { | ||
| 171 | uint32_t name, type; | ||
| 172 | uint64_t flags, addr, ofs, size; | ||
| 173 | uint32_t link, info; | ||
| 174 | uint64_t align, entsize; | ||
| 175 | } ELF64sectheader; | ||
| 176 | typedef struct { | ||
| 177 | uint32_t name, value, size; | ||
| 178 | uint8_t info, other; | ||
| 179 | uint16_t sectidx; | ||
| 180 | } ELF32symbol; | ||
| 181 | typedef struct { | ||
| 182 | uint32_t name; | ||
| 183 | uint8_t info, other; | ||
| 184 | uint16_t sectidx; | ||
| 185 | uint64_t value, size; | ||
| 186 | } ELF64symbol; | ||
| 187 | typedef struct { | ||
| 188 | ELF32header hdr; | ||
| 189 | ELF32sectheader sect[6]; | ||
| 190 | ELF32symbol sym[2]; | ||
| 191 | uint8_t space[4096]; | ||
| 192 | } ELF32obj; | ||
| 193 | typedef struct { | ||
| 194 | ELF64header hdr; | ||
| 195 | ELF64sectheader sect[6]; | ||
| 196 | ELF64symbol sym[2]; | ||
| 197 | uint8_t space[4096]; | ||
| 198 | } ELF64obj; | ||
| 199 | ]] | ||
| 200 | local symname = LJBC_PREFIX..ctx.modname | ||
| 201 | local is64, isbe = false, false | ||
| 202 | if ctx.arch == "x64" then | ||
| 203 | is64 = true | ||
| 204 | elseif ctx.arch == "ppc" or ctx.arch == "ppcspe" or ctx.arch == "mips" then | ||
| 205 | isbe = true | ||
| 206 | end | ||
| 207 | |||
| 208 | -- Handle different host/target endianess. | ||
| 209 | local function f32(x) return x end | ||
| 210 | local f16, fofs = f32, f32 | ||
| 211 | if ffi.abi("be") ~= isbe then | ||
| 212 | f32 = bit.bswap | ||
| 213 | function f16(x) return bit.rshift(bit.bswap(x), 16) end | ||
| 214 | if is64 then | ||
| 215 | function fofs(x) return bit.bswap(x)*(2ll^32) end | ||
| 216 | else | ||
| 217 | fofs = f32 | ||
| 218 | end | ||
| 219 | end | ||
| 220 | |||
| 221 | -- Create ELF object and fill in header. | ||
| 222 | local o = ffi.new(is64 and "ELF64obj" or "ELF32obj") | ||
| 223 | local hdr = o.hdr | ||
| 224 | if ctx.os == "bsd" or ctx.os == "other" then -- Determine native hdr.eosabi. | ||
| 225 | local bf = assert(io.open("/bin/ls", "rb")) | ||
| 226 | local bs = bf:read(9) | ||
| 227 | bf:close() | ||
| 228 | ffi.copy(o, bs, 9) | ||
| 229 | check(hdr.emagic[0] == 127, "no support for writing native object files") | ||
| 230 | else | ||
| 231 | hdr.emagic = "\127ELF" | ||
| 232 | hdr.eosabi = ({ freebsd=9, netbsd=2, openbsd=12, solaris=6 })[ctx.os] or 0 | ||
| 233 | end | ||
| 234 | hdr.eclass = is64 and 2 or 1 | ||
| 235 | hdr.eendian = isbe and 2 or 1 | ||
| 236 | hdr.eversion = 1 | ||
| 237 | hdr.type = f16(1) | ||
| 238 | hdr.machine = f16(({ x86=3, x64=62, arm=40, ppc=20, ppcspe=20, mips=8, mipsel=8 })[ctx.arch]) | ||
| 239 | if ctx.arch == "mips" or ctx.arch == "mipsel" then | ||
| 240 | hdr.flags = 0x50001006 | ||
| 241 | end | ||
| 242 | hdr.version = f32(1) | ||
| 243 | hdr.shofs = fofs(ffi.offsetof(o, "sect")) | ||
| 244 | hdr.ehsize = f16(ffi.sizeof(hdr)) | ||
| 245 | hdr.shentsize = f16(ffi.sizeof(o.sect[0])) | ||
| 246 | hdr.shnum = f16(6) | ||
| 247 | hdr.shstridx = f16(2) | ||
| 248 | |||
| 249 | -- Fill in sections and symbols. | ||
| 250 | local sofs, ofs = ffi.offsetof(o, "space"), 1 | ||
| 251 | for i,name in ipairs{ | ||
| 252 | ".symtab", ".shstrtab", ".strtab", ".rodata", ".note.GNU-stack", | ||
| 253 | } do | ||
| 254 | local sect = o.sect[i] | ||
| 255 | sect.align = fofs(1) | ||
| 256 | sect.name = f32(ofs) | ||
| 257 | ffi.copy(o.space+ofs, name) | ||
| 258 | ofs = ofs + #name+1 | ||
| 259 | end | ||
| 260 | o.sect[1].type = f32(2) -- .symtab | ||
| 261 | o.sect[1].link = f32(3) | ||
| 262 | o.sect[1].info = f32(1) | ||
| 263 | o.sect[1].align = fofs(8) | ||
| 264 | o.sect[1].ofs = fofs(ffi.offsetof(o, "sym")) | ||
| 265 | o.sect[1].entsize = fofs(ffi.sizeof(o.sym[0])) | ||
| 266 | o.sect[1].size = fofs(ffi.sizeof(o.sym)) | ||
| 267 | o.sym[1].name = f32(1) | ||
| 268 | o.sym[1].sectidx = f16(4) | ||
| 269 | o.sym[1].size = fofs(#s) | ||
| 270 | o.sym[1].info = 17 | ||
| 271 | o.sect[2].type = f32(3) -- .shstrtab | ||
| 272 | o.sect[2].ofs = fofs(sofs) | ||
| 273 | o.sect[2].size = fofs(ofs) | ||
| 274 | o.sect[3].type = f32(3) -- .strtab | ||
| 275 | o.sect[3].ofs = fofs(sofs + ofs) | ||
| 276 | o.sect[3].size = fofs(#symname+1) | ||
| 277 | ffi.copy(o.space+ofs+1, symname) | ||
| 278 | ofs = ofs + #symname + 2 | ||
| 279 | o.sect[4].type = f32(1) -- .rodata | ||
| 280 | o.sect[4].flags = fofs(2) | ||
| 281 | o.sect[4].ofs = fofs(sofs + ofs) | ||
| 282 | o.sect[4].size = fofs(#s) | ||
| 283 | o.sect[5].type = f32(1) -- .note.GNU-stack | ||
| 284 | o.sect[5].ofs = fofs(sofs + ofs + #s) | ||
| 285 | |||
| 286 | -- Write ELF object file. | ||
| 287 | local fp = savefile(output, "wb") | ||
| 288 | fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs)) | ||
| 289 | bcsave_tail(fp, output, s) | ||
| 290 | end | ||
| 291 | |||
| 292 | local function bcsave_peobj(ctx, output, s, ffi) | ||
| 293 | ffi.cdef[[ | ||
| 294 | typedef struct { | ||
| 295 | uint16_t arch, nsects; | ||
| 296 | uint32_t time, symtabofs, nsyms; | ||
| 297 | uint16_t opthdrsz, flags; | ||
| 298 | } PEheader; | ||
| 299 | typedef struct { | ||
| 300 | char name[8]; | ||
| 301 | uint32_t vsize, vaddr, size, ofs, relocofs, lineofs; | ||
| 302 | uint16_t nreloc, nline; | ||
| 303 | uint32_t flags; | ||
| 304 | } PEsection; | ||
| 305 | typedef struct __attribute((packed)) { | ||
| 306 | union { | ||
| 307 | char name[8]; | ||
| 308 | uint32_t nameref[2]; | ||
| 309 | }; | ||
| 310 | uint32_t value; | ||
| 311 | int16_t sect; | ||
| 312 | uint16_t type; | ||
| 313 | uint8_t scl, naux; | ||
| 314 | } PEsym; | ||
| 315 | typedef struct __attribute((packed)) { | ||
| 316 | uint32_t size; | ||
| 317 | uint16_t nreloc, nline; | ||
| 318 | uint32_t cksum; | ||
| 319 | uint16_t assoc; | ||
| 320 | uint8_t comdatsel, unused[3]; | ||
| 321 | } PEsymaux; | ||
| 322 | typedef struct { | ||
| 323 | PEheader hdr; | ||
| 324 | PEsection sect[2]; | ||
| 325 | // Must be an even number of symbol structs. | ||
| 326 | PEsym sym0; | ||
| 327 | PEsymaux sym0aux; | ||
| 328 | PEsym sym1; | ||
| 329 | PEsymaux sym1aux; | ||
| 330 | PEsym sym2; | ||
| 331 | PEsym sym3; | ||
| 332 | uint32_t strtabsize; | ||
| 333 | uint8_t space[4096]; | ||
| 334 | } PEobj; | ||
| 335 | ]] | ||
| 336 | local symname = LJBC_PREFIX..ctx.modname | ||
| 337 | local is64 = false | ||
| 338 | if ctx.arch == "x86" then | ||
| 339 | symname = "_"..symname | ||
| 340 | elseif ctx.arch == "x64" then | ||
| 341 | is64 = true | ||
| 342 | end | ||
| 343 | local symexport = " /EXPORT:"..symname..",DATA " | ||
| 344 | |||
| 345 | -- The file format is always little-endian. Swap if the host is big-endian. | ||
| 346 | local function f32(x) return x end | ||
| 347 | local f16 = f32 | ||
| 348 | if ffi.abi("be") then | ||
| 349 | f32 = bit.bswap | ||
| 350 | function f16(x) return bit.rshift(bit.bswap(x), 16) end | ||
| 351 | end | ||
| 352 | |||
| 353 | -- Create PE object and fill in header. | ||
| 354 | local o = ffi.new("PEobj") | ||
| 355 | local hdr = o.hdr | ||
| 356 | hdr.arch = f16(({ x86=0x14c, x64=0x8664, arm=0x1c0, ppc=0x1f2, mips=0x366, mipsel=0x366 })[ctx.arch]) | ||
| 357 | hdr.nsects = f16(2) | ||
| 358 | hdr.symtabofs = f32(ffi.offsetof(o, "sym0")) | ||
| 359 | hdr.nsyms = f32(6) | ||
| 360 | |||
| 361 | -- Fill in sections and symbols. | ||
| 362 | o.sect[0].name = ".drectve" | ||
| 363 | o.sect[0].size = f32(#symexport) | ||
| 364 | o.sect[0].flags = f32(0x00100a00) | ||
| 365 | o.sym0.sect = f16(1) | ||
| 366 | o.sym0.scl = 3 | ||
| 367 | o.sym0.name = ".drectve" | ||
| 368 | o.sym0.naux = 1 | ||
| 369 | o.sym0aux.size = f32(#symexport) | ||
| 370 | o.sect[1].name = ".rdata" | ||
| 371 | o.sect[1].size = f32(#s) | ||
| 372 | o.sect[1].flags = f32(0x40300040) | ||
| 373 | o.sym1.sect = f16(2) | ||
| 374 | o.sym1.scl = 3 | ||
| 375 | o.sym1.name = ".rdata" | ||
| 376 | o.sym1.naux = 1 | ||
| 377 | o.sym1aux.size = f32(#s) | ||
| 378 | o.sym2.sect = f16(2) | ||
| 379 | o.sym2.scl = 2 | ||
| 380 | o.sym2.nameref[1] = f32(4) | ||
| 381 | o.sym3.sect = f16(-1) | ||
| 382 | o.sym3.scl = 2 | ||
| 383 | o.sym3.value = f32(1) | ||
| 384 | o.sym3.name = "@feat.00" -- Mark as SafeSEH compliant. | ||
| 385 | ffi.copy(o.space, symname) | ||
| 386 | local ofs = #symname + 1 | ||
| 387 | o.strtabsize = f32(ofs + 4) | ||
| 388 | o.sect[0].ofs = f32(ffi.offsetof(o, "space") + ofs) | ||
| 389 | ffi.copy(o.space + ofs, symexport) | ||
| 390 | ofs = ofs + #symexport | ||
| 391 | o.sect[1].ofs = f32(ffi.offsetof(o, "space") + ofs) | ||
| 392 | |||
| 393 | -- Write PE object file. | ||
| 394 | local fp = savefile(output, "wb") | ||
| 395 | fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs)) | ||
| 396 | bcsave_tail(fp, output, s) | ||
| 397 | end | ||
| 398 | |||
| 399 | local function bcsave_machobj(ctx, output, s, ffi) | ||
| 400 | check(false, "NYI: no support for writing OSX object files") | ||
| 401 | end | ||
| 402 | |||
| 403 | local function bcsave_obj(ctx, output, s) | ||
| 404 | local ok, ffi = pcall(require, "ffi") | ||
| 405 | check(ok, "FFI library required to write this file type") | ||
| 406 | if ctx.os == "windows" then | ||
| 407 | return bcsave_peobj(ctx, output, s, ffi) | ||
| 408 | elseif ctx.os == "osx" then | ||
| 409 | return bcsave_machobj(ctx, output, s, ffi) | ||
| 410 | else | ||
| 411 | return bcsave_elfobj(ctx, output, s, ffi) | ||
| 412 | end | ||
| 413 | end | ||
| 414 | |||
| 415 | ------------------------------------------------------------------------------ | ||
| 416 | |||
| 417 | local function bclist(input, output) | ||
| 418 | local f = readfile(input) | ||
| 419 | require("jit.bc").dump(f, savefile(output, "w"), true) | ||
| 420 | end | ||
| 421 | |||
| 422 | local function bcsave(ctx, input, output) | ||
| 423 | local f = readfile(input) | ||
| 424 | local s = string.dump(f, ctx.strip) | ||
| 425 | local t = ctx.type | ||
| 426 | if not t then | ||
| 427 | t = detecttype(output) | ||
| 428 | ctx.type = t | ||
| 429 | end | ||
| 430 | if t == "raw" then | ||
| 431 | bcsave_raw(output, s) | ||
| 432 | else | ||
| 433 | if not ctx.modname then ctx.modname = detectmodname(input) end | ||
| 434 | if t == "obj" then | ||
| 435 | bcsave_obj(ctx, output, s) | ||
| 436 | else | ||
| 437 | bcsave_c(ctx, output, s) | ||
| 438 | end | ||
| 439 | end | ||
| 440 | end | ||
| 441 | |||
| 442 | local function docmd(...) | ||
| 443 | local arg = {...} | ||
| 444 | local n = 1 | ||
| 445 | local list = false | ||
| 446 | local ctx = { | ||
| 447 | strip = true, arch = jit.arch, os = string.lower(jit.os), | ||
| 448 | type = false, modname = false, | ||
| 449 | } | ||
| 450 | while n <= #arg do | ||
| 451 | local a = arg[n] | ||
| 452 | if type(a) == "string" and string.sub(a, 1, 1) == "-" and a ~= "-" then | ||
| 453 | table.remove(arg, n) | ||
| 454 | if a == "--" then break end | ||
| 455 | for m=2,#a do | ||
| 456 | local opt = string.sub(a, m, m) | ||
| 457 | if opt == "l" then | ||
| 458 | list = true | ||
| 459 | elseif opt == "s" then | ||
| 460 | ctx.strip = true | ||
| 461 | elseif opt == "g" then | ||
| 462 | ctx.strip = false | ||
| 463 | else | ||
| 464 | if arg[n] == nil or m ~= #a then usage() end | ||
| 465 | if opt == "e" then | ||
| 466 | if n ~= 1 then usage() end | ||
| 467 | arg[1] = check(loadstring(arg[1])) | ||
| 468 | elseif opt == "n" then | ||
| 469 | ctx.modname = checkmodname(table.remove(arg, n)) | ||
| 470 | elseif opt == "t" then | ||
| 471 | ctx.type = checkarg(table.remove(arg, n), map_type, "file type") | ||
| 472 | elseif opt == "a" then | ||
| 473 | ctx.arch = checkarg(table.remove(arg, n), map_arch, "architecture") | ||
| 474 | elseif opt == "o" then | ||
| 475 | ctx.os = checkarg(table.remove(arg, n), map_os, "OS name") | ||
| 476 | else | ||
| 477 | usage() | ||
| 478 | end | ||
| 479 | end | ||
| 480 | end | ||
| 481 | else | ||
| 482 | n = n + 1 | ||
| 483 | end | ||
| 484 | end | ||
| 485 | if list then | ||
| 486 | if #arg == 0 or #arg > 2 then usage() end | ||
| 487 | bclist(arg[1], arg[2] or "-") | ||
| 488 | else | ||
| 489 | if #arg ~= 2 then usage() end | ||
| 490 | bcsave(ctx, arg[1], arg[2]) | ||
| 491 | end | ||
| 492 | end | ||
| 493 | |||
| 494 | ------------------------------------------------------------------------------ | ||
| 495 | |||
| 496 | -- Public module functions. | ||
| 497 | module(...) | ||
| 498 | |||
| 499 | start = docmd -- Process -b command line option. | ||
| 500 | |||
