diff options
-rw-r--r-- | nerv/init.lua | 103 | ||||
-rw-r--r-- | nerv/test/parse_args.lua | 16 |
2 files changed, 119 insertions, 0 deletions
diff --git a/nerv/init.lua b/nerv/init.lua index 4aa7a45..fdfd531 100644 --- a/nerv/init.lua +++ b/nerv/init.lua @@ -172,6 +172,109 @@ function nerv.include(filename) return dofile(nerv.dirname(caller) .. filename) end +--- Parse the command-line options and arguments +function nerv.parse_args(argv, options) + local is_opt_exp = "^[-](.*)$" + local sim_opt_exp = "^[-]([a-z]+)$" + local opt_exp = "^[-][-]([^=]+)$" + local opt_with_val_exp = "^[-][-]([^=]+)=([^=]+)$" + local opts = {} + local sopts = {} + local args = {} + local function err() + nerv.error("invalid format of option specification") + end + for _, v in ipairs(options) do + if type(v) ~= "table" or + (v[1] == nil and v[2] == nil) or + v[3] == nil then + err() + end + opt_full = v[1] + opt_short = v[2] + opt_type = v[3] + local opt_meta = {type = opt_type, + desc = v.desc or "", + val = v.default} + if opt_short ~= nil then + if type(opt_short) ~= "string" then err() end + if opt_type ~= "bool" then + nerv.error("only boolean option could have short form") + end + sopts[opt_short] = opt_meta + end + if opt_full ~= nil then + if type(opt_full) ~= "string" then err() end + opts[opt_full] = opt_meta + end + end + for _, token in ipairs(argv) do + if token:match(is_opt_exp) then + local k = token:match(sim_opt_exp) + if k then + for c in k:gmatch"." do + if sopts[c] then + sopts[c].val = true + else + nerv.error("invalid option -%s", c) + end + end + else + local k = token:match(opt_exp) + if k then + if opts[k] == nil then + nerv.error("invalid option %s", token) + end + if opts[k].type ~= "bool" then + nerv.error("invalid option --%s: " .. + "a %s value needs to be specified", + k, opts[k].type) + else + opts[k].val = true + end + else + local k, v = token:match(opt_with_val_exp) + if k then + if opts[k] == nil then + nerv.error("invalid option %s", token) + end + if opts[k].type == "bool" then + if v == "yes" then + opts[k].val = true + elseif v == "no" then + opts[k].val = false + else + nerv.error("bool value should be \"yes\" or \"no\"") + end + elseif opts[k].type == "int" then + local t = tonumber(v) + opts[k].val = t + if t == nil or math.floor(t) ~= t then + nerv.error("int value is expected") + end + elseif opts[k].type == "float" then + local t = tonumber(v) + opts[k].val = t + if t == nil then + nerv.error("float value is expected") + end + elseif opts[k].type == "string" then + opts[k].val = v + else + nerv.error("unrecognized type %s", opts[k].type) + end + else + nerv.error("unrecognized option %s", token) + end + end + end + else + table.insert(args, token) + end + end + return args, opts +end + -- the following lines trigger the initialization of basic modules nerv.include('matrix/init.lua') diff --git a/nerv/test/parse_args.lua b/nerv/test/parse_args.lua new file mode 100644 index 0000000..7146c3b --- /dev/null +++ b/nerv/test/parse_args.lua @@ -0,0 +1,16 @@ +args, opts = nerv.parse_args( + {"arg1", "arg2", "-abcd", "arg3", + "--hehe", "--oh=no", "--uid=43", + "highfive", "--str=hello"}, + + {{"abandon", "a", "bool", default = false, desc = "abandon your belief"}, + {"bullshit", "b", "bool", default = false, desc = "start to bullshit"}, + {"cheat", "c", "bool", default = false, desc = "try to cheat"}, + {"delete", "d", "bool", default = false, desc = "remove everything"}, + {"hehe", "h", "bool", default = false, desc = "233333"}, + {"oh", "o", "bool", default = true, desc = "oh yes!"}, + {"uid", nil, "int", desc = "user uid"}, + {"str", nil, "string", desc = "test string"}} + ) + +print(table.tostring(args), table.tostring(opts)) |