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  |