144 lines
2.5 KiB
Go
144 lines
2.5 KiB
Go
|
package opts
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
ErrInvalidShortOption = errors.New("invalid short option")
|
||
|
ErrCannotChainOption = errors.New("cannot chain option as it takes an argument")
|
||
|
)
|
||
|
|
||
|
func (s Set) Parse(args []string) (restArgs []string, err error) {
|
||
|
for i := 0; i < len(args); i++ {
|
||
|
arg := args[i]
|
||
|
|
||
|
// Handle regular argument
|
||
|
if !strings.HasPrefix(arg, "-") {
|
||
|
restArgs = append(restArgs, arg)
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// Handle options terminator
|
||
|
if arg == "--" {
|
||
|
restArgs = append(restArgs, args[i+1:]...)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Handle long option
|
||
|
if strings.HasPrefix(arg, "--") {
|
||
|
longName := arg[2:]
|
||
|
value := ""
|
||
|
|
||
|
equals := strings.Index(longName, "=")
|
||
|
if equals > 0 {
|
||
|
longName = longName[:equals]
|
||
|
value = longName[equals+1:]
|
||
|
} else if i < len(args)-1 && !strings.HasPrefix(args[i+1], "-") {
|
||
|
value = args[i+1]
|
||
|
i++
|
||
|
}
|
||
|
|
||
|
parsed := false
|
||
|
for _, opt := range s {
|
||
|
if opt.Name() != longName {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if err = opt.Parse(value); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
parsed = true
|
||
|
break
|
||
|
}
|
||
|
|
||
|
if !parsed {
|
||
|
restArgs = append(restArgs, arg)
|
||
|
}
|
||
|
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// Handle short option
|
||
|
shortNames := arg[1:]
|
||
|
if len(shortNames) == 0 {
|
||
|
err = ErrInvalidShortOption
|
||
|
} else if len(shortNames) == 1 {
|
||
|
parsed := false
|
||
|
value := ""
|
||
|
if i < len(args)-1 && !strings.HasPrefix(args[i+1], "-") {
|
||
|
value = args[i+1]
|
||
|
i++
|
||
|
}
|
||
|
|
||
|
for _, opt := range s {
|
||
|
if opt.ShortName() != shortNames {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if err = opt.Parse(value); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
parsed = true
|
||
|
break
|
||
|
}
|
||
|
|
||
|
if !parsed {
|
||
|
restArgs = append(restArgs, arg)
|
||
|
}
|
||
|
} else {
|
||
|
for j := 0; j < len(shortNames); j++ {
|
||
|
shortName := shortNames[j]
|
||
|
value := ""
|
||
|
takesValue := false
|
||
|
parsed := false
|
||
|
|
||
|
for _, opt := range s {
|
||
|
if opt.ShortName() != string(shortName) {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if opt.TakesArg() {
|
||
|
if j > 0 {
|
||
|
err = ErrCannotChainOption
|
||
|
return
|
||
|
}
|
||
|
|
||
|
takesValue = true
|
||
|
value = shortNames[j+1:]
|
||
|
value = strings.TrimPrefix(value, "=")
|
||
|
if len(value) == 0 && i < len(args)-1 && !strings.HasPrefix(args[i+1], "-") {
|
||
|
value = args[i+1]
|
||
|
i++
|
||
|
}
|
||
|
j = len(shortNames)
|
||
|
}
|
||
|
|
||
|
parsed = true
|
||
|
|
||
|
if err = opt.Parse(value); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
break
|
||
|
}
|
||
|
|
||
|
if !parsed {
|
||
|
if takesValue {
|
||
|
restArgs = append(restArgs, arg)
|
||
|
break
|
||
|
} else {
|
||
|
restArgs = append(restArgs, fmt.Sprintf("-%c", shortName))
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return
|
||
|
}
|