diff options
| author | Opportunity <[email protected]> | 2020-01-15 11:24:36 +0800 |
|---|---|---|
| committer | Opportunity <[email protected]> | 2020-01-15 11:24:36 +0800 |
| commit | 9862d1b95fa5978eaf24d65f1ca5f151d410a14b (patch) | |
| tree | 2cac28495cfc70402a60d1b244dc4a801d484eb5 /xmake/core/base/cli.lua | |
| parent | eb1effdccd96425375af083d45a94a790f0c6d56 (diff) | |
Improve options parsing
Diffstat (limited to 'xmake/core/base/cli.lua')
| -rw-r--r-- | xmake/core/base/cli.lua | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/xmake/core/base/cli.lua b/xmake/core/base/cli.lua new file mode 100644 index 000000000..3e78fcdbc --- /dev/null +++ b/xmake/core/base/cli.lua @@ -0,0 +1,122 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-2020, TBOOX Open Source Group. +-- +-- @author OpportunityLiu +-- @file cli.lua +-- + +-- define module +local cli = cli or {} +local segment = cli._segment or {} + +-- load modules +local string = require("base/string") +local hashset = require("base/hashset") + +segment.__index = segment + +function segment:__tostring() + return self.string +end + +function segment:__todisplay() + return string.format("${color.dump.string}%s${reset} ${color.dump.keyword}(%s)${reset}", self.string, self.type) +end + +function segment:is(type) + return self.type == type +end + +function cli._make_segment(type, string, argv, argi, obj) + obj.type = type + obj.string = string + obj.argv = argv + obj.argi = argi + return setmetatable(obj, segment) +end + +function cli._make_arg(value, argv, argi) + return cli._make_segment('arg', value, argv, argi, { value = value }) +end + +function cli._make_flag(key, short, argv, argi) + return cli._make_segment('flag', #key == 1 and ('-' .. key) or ('--' .. key), argv, argi, { key = key, value = true, short = short or false }) +end + +function cli._make_option(key, value, short, argv, argi) + return cli._make_segment('option', #key == 1 and ('-' .. key .. value) or ('--' .. key .. '=' .. value), argv, argi, { key = key, value = value, short = short or false }) +end + +function cli.parse(args, ...) + return cli.parsev(os.argv(args), ...) +end + +function cli.parsev(argv, flags) + + local parsed = {} + local raw = false + local index = 1 + local value = nil + flags = hashset.from(flags or {}) + + while index <= #argv do + value = argv[index] + if raw or not value:startswith('-') or #value < 2 then + -- all args after '--' or first arg, args don't start with '-', and short args (include a single char '-') + raw = true + table.insert(parsed, cli._make_arg(value, argv, index)) + elseif value == '--' then + -- stop parsing after '--' + raw = true + table.insert(parsed, cli._make_segment('sep', '--', argv, index, {})) + elseif value:startswith('--') then + -- '--key:value', '--key=value', '--long-flag' + local sep = value:find('[=:]', 3, false) + if sep then + table.insert(parsed, cli._make_option(value:sub(3, sep - 1), value:sub(sep + 1), false, argv, index)) + else + table.insert(parsed, cli._make_flag(value:sub(3), false, argv, index)) + end + else + local strp = 2 + while strp <= #value do + local ch = value:sub(strp, strp) + if flags:has(ch) then + -- is a flag + table.insert(parsed, cli._make_flag(ch, true, argv, index)) + else + -- is an option + if strp == #value then + -- is last char, use next arg as value + table.insert(parsed, cli._make_option(ch, argv[index + 1] or "", true, argv, index)) + index = index + 1 + else + -- is not last char, use remaining as value + table.insert(parsed, cli._make_option(ch, value:sub(strp + 1), true, argv, index)) + strp = #value + end + end + strp = strp + 1 + end + end + index = index + 1 + end + return parsed +end + +cli._segment = segment +-- return module +return cli
\ No newline at end of file |
