summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nerv/init.lua103
-rw-r--r--nerv/test/parse_args.lua16
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))