-
Notifications
You must be signed in to change notification settings - Fork 0
/
normalize.go
151 lines (130 loc) · 3.45 KB
/
normalize.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package nzflag
import (
"os"
"strings"
)
type FlagOption int
const (
None FlagOption = 0
HasValue FlagOption = 1 << iota
)
// App holds config for normalize
type App struct {
FlagOption map[string]FlagOption
}
// New returns new App instance
func New() *App {
return &App{map[string]FlagOption{}}
}
// Flag sets flag option
func (app *App) Flag(name string, opt FlagOption) {
switch opt {
case None:
app.FlagOption[name] = 0
case HasValue:
app.FlagOption[name] = app.FlagOption[name] | opt
default:
panic("Unknown flag option")
}
}
// FlagHasValue returns true if flag has value
func (app *App) FlagHasValue(name string) bool {
return app.FlagOption[name]&HasValue == HasValue
}
func getFlagValue(i int, args []string) string {
if i < len(args) && !strings.HasPrefix(args[i], "-") {
return args[i]
}
return ""
}
func splitByEq(s string) (string, string) {
splited := strings.SplitN(s, "=", 2)
if len(splited) == 1 {
return splited[0], ""
}
return splited[0], splited[1]
}
func parseValue(value string) []string {
if len(value) == 0 {
return []string{}
}
return strings.Split(value, ",")
}
func (app *App) processLongFlag(prefix string, args []string) (Value, int) {
i := 0
text := strings.TrimPrefix(args[i], prefix)
name, value := splitByEq(text)
var flag *Flag
if len(value) == 0 && app.FlagHasValue(name) {
if fv := getFlagValue(i+1, args); len(fv) > 0 {
value = fv
i++
}
}
flag = NewFlag(name, parseValue(value)...)
return flag, i
}
func (app *App) processShortFlag(prefix string, args []string) ([]Value, int) {
text := strings.TrimPrefix(args[0], prefix)
i := 0
first := string(text[0])
// -foo -> -f=oo
if len(text) > 1 && app.FlagHasValue(first) {
return []Value{NewFlag(first, parseValue(text[1:])...)}, 0
}
names, value := splitByEq(text)
lastName := string(names[len(names)-1])
flags := make([]Value, 0, len(names))
for _, name := range names[:len(names)-1] {
flags = append(flags, NewFlag(string(name)))
}
if len(value) == 0 && app.FlagHasValue(lastName) {
if fv := getFlagValue(i+1, args); len(fv) > 0 {
value = fv
i++
}
}
flags = append(flags, NewFlag(lastName, parseValue(value)...))
return flags, i
}
// Normalize parses argv
func (app *App) Normalize(argv []string) NormalizedArgv {
normalized := make([]Value, 0)
forceArgMode := false
for i := 0; i < len(argv); i++ {
v := argv[i]
switch {
case v == "--":
forceArgMode = true
normalized = append(normalized, NewArg(v))
case forceArgMode:
normalized = append(normalized, NewArg(v))
case len(strings.Trim(v, "-")) == 0: // hyphen only
normalized = append(normalized, NewArg(v))
case strings.HasPrefix(v, "--"):
flag, n := app.processLongFlag("--", argv[i:])
i += n
normalized = append(normalized, flag)
case strings.HasPrefix(v, "-"):
flags, n := app.processShortFlag("-", argv[i:])
i += n
normalized = append(normalized, flags...)
default:
normalized = append(normalized, NewArg(v))
}
}
return normalized
}
// NormalizeToStrings normalize argv and returns result as text slice
func (app *App) NormalizeToStrings(argv []string) []string {
normalized := app.Normalize(argv)
return normalized.Strings()
}
// NormalizeArgs is same Normalize except use os.Args
func (app *App) NormalizeArgs() []Value {
return app.Normalize(os.Args[1:])
}
// NormalizeArgsToStrings is same NormalizeToStrings except use os.Args
func (app *App) NormalizeArgsToStrings() []string {
return app.NormalizeToStrings(os.Args[1:])
}