// Package cli holds small command-line helpers shared by the sshtools binaries. package cli import "strings" // Split reorders a raw argument list so that Go's flag package can parse it // even when flags follow positional arguments, as in: // // golink user@host -p secret -port 22 -command uptime // // flag.Parse stops at the first non-flag argument, so that raw order would // otherwise leave every flag unset and silently do the wrong thing. Split walks // the arguments once and collects flags (together with the value of any flag // named in takesValue) into flags, and everything else into positional. // // The caller is expected to concatenate the results: // // flags, positional := cli.Split(os.Args[1:], valueFlags) // fs.Parse(append(flags, positional...)) // // A literal "--" ends flag processing; everything after it is positional. func Split(args []string, takesValue map[string]bool) (flags, positional []string) { for i := 0; i < len(args); i++ { arg := args[i] if arg == "--" { positional = append(positional, args[i+1:]...) break } if !isFlag(arg) { positional = append(positional, arg) continue } flags = append(flags, arg) name := strings.TrimLeft(arg, "-") if strings.ContainsRune(name, '=') { continue // -port=22 carries its value inline } if takesValue[name] && i+1 < len(args) { i++ flags = append(flags, args[i]) } } return flags, positional } // isFlag reports whether arg looks like a flag rather than a positional value. // A bare "-" and negative numbers are treated as positional. func isFlag(arg string) bool { if len(arg) < 2 || arg[0] != '-' { return false } return arg[1] < '0' || arg[1] > '9' }