package main import ( "fmt" "os" "strconv" "strings" ) type Options struct { Verbose bool Count int Name string Args []string } // ParseArgs parses flags and collects positional arguments. func ParseArgs(args []string) (Options, error) { opts := Options{Count: 1} for i := 0; i < len(args); i++ { arg := args[i] if arg == "--" { opts.Args = append(opts.Args, args[i+1:]...) break } switch { case arg == "-v" || arg == "--verbose": opts.Verbose = true case arg == "-n" || arg == "--name": if i+1 >= len(args) { return opts, fmt.Errorf("%s requires a value", arg) } i++ opts.Name = args[i] case strings.HasPrefix(arg, "--name="): opts.Name = strings.TrimPrefix(arg, "--name=") case arg == "-c" || arg == "--count": if i+1 >= len(args) { return opts, fmt.Errorf("%s requires a value", arg) } i++ count, err := strconv.Atoi(args[i]) if err != nil || count < 1 { return opts, fmt.Errorf("invalid count %q", args[i]) } opts.Count = count case strings.HasPrefix(arg, "--count="): value := strings.TrimPrefix(arg, "--count=") count, err := strconv.Atoi(value) if err != nil || count < 1 { return opts, fmt.Errorf("invalid count %q", value) } opts.Count = count case strings.HasPrefix(arg, "-"): return opts, fmt.Errorf("unknown option %q", arg) default: opts.Args = append(opts.Args, arg) } } return opts, nil } // runTests provides a couple of lightweight parser checks. func runTests() error { tests := []struct { args []string want Options }{ { args: []string{"--verbose", "--name=Ada", "--count", "2", "file.txt"}, want: Options{Verbose: true, Name: "Ada", Count: 2, Args: []string{"file.txt"}}, }, { args: []string{"--", "--verbose"}, want: Options{Count: 1, Args: []string{"--verbose"}}, }, } for i, test := range tests { got, err := ParseArgs(test.args) if err != nil { return fmt.Errorf("test %d: unexpected error: %w", i+1, err) } if fmt.Sprintf("%#v", got) != fmt.Sprintf("%#v", test.want) { return fmt.Errorf("test %d: got %#v, want %#v", i+1, got, test.want) } } return nil } func main() { if len(os.Args) == 2 && os.Args[1] == "--self-test" { if err := runTests(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } fmt.Println("tests passed") return } opts, err := ParseArgs(os.Args[1:]) if err != nil { fmt.Fprintln(os.Stderr, "error:", err) os.Exit(2) } fmt.Printf("verbose=%t name=%q count=%d args=%v\n", opts.Verbose, opts.Name, opts.Count, opts.Args) }