diff options
Diffstat (limited to 'client/system/cli.gd')
-rw-r--r-- | client/system/cli.gd | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/client/system/cli.gd b/client/system/cli.gd new file mode 100644 index 00000000..b6ba8eef --- /dev/null +++ b/client/system/cli.gd @@ -0,0 +1,112 @@ +# Hurry Curry! - a game about cooking +# Copyright (C) 2025 Hurry Curry! contributors +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, version 3 of the License only. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +extends Node +class_name Cli + +enum Mode { FLAG, OPTION, MULTI_OPTION, POSITIONAL } +class Option: + var short #: String? + var long: String + var mode: Mode + var help: String + func _init(s, l: String, m: Mode, h: String): + short = s; long = l; mode = m; help = h + +static var OPTIONS := [ + Option.new("h", "help", Mode.FLAG, "Show help"), + Option.new("s", "setting", Mode.MULTI_OPTION, "Per-launch setting override"), + Option.new(null, "connect_address", Mode.POSITIONAL, "Connect to a server directly without menu interaction") +] + +static var opts = {} #: Dictionary[String, Variant] + +static func init() -> bool: + if not parse(): return false + if opts.has("help"): + print_help() + return false + return true + +static func print_help(): + print("OPTIONS:\n") + for opt in OPTIONS: + var line = "" + if opt.mode == Mode.POSITIONAL: + line += "<" + opt.long.to_upper() + ">" + else: + if opt.short: line += "-" + opt.short + ", " + line += "--" + opt.long + if opt.mode == Mode.OPTION or opt.mode == Mode.MULTI_OPTION: + line += " <VALUE>" + while line.length() < 25: line += " " + line += " " + opt.help + print(line) + +static func parse() -> bool: + var args := OS.get_cmdline_user_args() + while not args.is_empty(): + var arg := args[0] + args.remove_at(0) + if arg.begins_with("--"): + var long = arg.trim_prefix("--") + var opt_index = OPTIONS.find_custom(func(x): return x.long == long) + if opt_index == -1: + push_error("unknown long option \"%s\"" % long) + return false + if not _parse_opt(args, OPTIONS[opt_index]): return false + elif arg.begins_with("-"): + for short in arg.trim_prefix("-"): + var opt_index = OPTIONS.find_custom(func(x): return x.short == short) + if opt_index == -1: + push_error("unknown short option \"%s\"" % short) + return false + if not _parse_opt(args, OPTIONS[opt_index]): return false + else: + var opt_index = OPTIONS.find_custom(func(x): return x.mode == Mode.POSITIONAL) + if opt_index == -1: + push_error("no positional arguments") + return false + var opt = OPTIONS[opt_index] + opts[opt.long] = arg + + print("Parsed options: ", opts) + return true + +static func _parse_opt(args: Array[String], opt: Option) -> bool: + match opt.mode: + Mode.FLAG: + opts[opt.long] = true + return true + Mode.OPTION: + if args.is_empty(): + push_error("missing option value") + return false + opts[opt.long] = args[0] + args.remove_at(0) + return true + Mode.MULTI_OPTION: + if args.is_empty(): + push_error("missing option value") + return false + if not opts.has(opt.long): opts[opt.long] = [] + opts[opt.long].push_back(args[0]) + args.remove_at(0) + return true + Mode.POSITIONAL: + push_error("positional arg doesnt need flag") + return false + push_error("unreachable") + return false |