Skip to content

Commit b92b2e6

Browse files
authored
Add IPNetSlice (#15)
1 parent 387ae5f commit b92b2e6

File tree

2 files changed

+415
-0
lines changed

2 files changed

+415
-0
lines changed

ipnet_slice.go

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
package pflag
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"net"
7+
"strings"
8+
)
9+
10+
// -- ipNetSlice Value
11+
type ipNetSliceValue struct {
12+
value *[]net.IPNet
13+
changed bool
14+
}
15+
16+
func newIPNetSliceValue(val []net.IPNet, p *[]net.IPNet) *ipNetSliceValue {
17+
ipnsv := new(ipNetSliceValue)
18+
ipnsv.value = p
19+
*ipnsv.value = val
20+
return ipnsv
21+
}
22+
23+
// Set converts, and assigns, the comma-separated IPNet argument string representation as the []net.IPNet value of this flag.
24+
// If Set is called on a flag that already has a []net.IPNet assigned, the newly converted values will be appended.
25+
func (s *ipNetSliceValue) Set(val string) error {
26+
27+
// remove all quote characters
28+
rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "")
29+
30+
// read flag arguments with CSV parser
31+
ipNetStrSlice, err := readAsCSV(rmQuote.Replace(val))
32+
if err != nil && err != io.EOF {
33+
return err
34+
}
35+
36+
// parse ip values into slice
37+
out := make([]net.IPNet, 0, len(ipNetStrSlice))
38+
for _, ipNetStr := range ipNetStrSlice {
39+
_, n, err := net.ParseCIDR(strings.TrimSpace(ipNetStr))
40+
if err != nil {
41+
return fmt.Errorf("invalid string being converted to CIDR: %s", ipNetStr)
42+
}
43+
out = append(out, *n)
44+
}
45+
46+
if !s.changed {
47+
*s.value = out
48+
} else {
49+
*s.value = append(*s.value, out...)
50+
}
51+
52+
s.changed = true
53+
54+
return nil
55+
}
56+
57+
// Type returns a string that uniquely represents this flag's type.
58+
func (s *ipNetSliceValue) Type() string {
59+
return "ipNetSlice"
60+
}
61+
62+
// String defines a "native" format for this net.IPNet slice flag value.
63+
func (s *ipNetSliceValue) String() string {
64+
65+
ipNetStrSlice := make([]string, len(*s.value))
66+
for i, n := range *s.value {
67+
ipNetStrSlice[i] = n.String()
68+
}
69+
70+
out, _ := writeAsCSV(ipNetStrSlice)
71+
return "[" + out + "]"
72+
}
73+
74+
func ipNetSliceConv(val string) (interface{}, error) {
75+
val = strings.Trim(val, "[]")
76+
// Emtpy string would cause a slice with one (empty) entry
77+
if len(val) == 0 {
78+
return []net.IPNet{}, nil
79+
}
80+
ss := strings.Split(val, ",")
81+
out := make([]net.IPNet, len(ss))
82+
for i, sval := range ss {
83+
_, n, err := net.ParseCIDR(strings.TrimSpace(sval))
84+
if err != nil {
85+
return nil, fmt.Errorf("invalid string being converted to CIDR: %s", sval)
86+
}
87+
out[i] = *n
88+
}
89+
return out, nil
90+
}
91+
92+
// GetIPNetSlice returns the []net.IPNet value of a flag with the given name
93+
func (f *FlagSet) GetIPNetSlice(name string) ([]net.IPNet, error) {
94+
val, err := f.getFlagType(name, "ipNetSlice", ipNetSliceConv)
95+
if err != nil {
96+
return []net.IPNet{}, err
97+
}
98+
return val.([]net.IPNet), nil
99+
}
100+
101+
// MustGetIPNetSlice is like GetIPNetSlice, but panics on error.
102+
func (f *FlagSet) MustGetIPNetSlice(name string) []net.IPNet {
103+
val, err := f.GetIPNetSlice(name)
104+
if err != nil {
105+
panic(err)
106+
}
107+
return val
108+
}
109+
110+
// IPNetSliceVar defines a ipNetSlice flag with specified name, default value, and usage string.
111+
// The argument p points to a []net.IPNet variable in which to store the value of the flag.
112+
func (f *FlagSet) IPNetSliceVar(p *[]net.IPNet, name string, value []net.IPNet, usage string) {
113+
f.IPNetSliceVarP(p, name, "", value, usage)
114+
}
115+
116+
// IPNetSliceVarP is like IPNetSliceVar, but accepts a shorthand letter that can be used after a single dash.
117+
func (f *FlagSet) IPNetSliceVarP(p *[]net.IPNet, name, shorthand string, value []net.IPNet, usage string) {
118+
f.VarP(newIPNetSliceValue(value, p), name, shorthand, usage)
119+
}
120+
121+
// IPNetSliceVarS is like IPNetSliceVar, but accepts a shorthand letter that can be used after a single dash, alone.
122+
func (f *FlagSet) IPNetSliceVarS(p *[]net.IPNet, name, shorthand string, value []net.IPNet, usage string) {
123+
f.VarS(newIPNetSliceValue(value, p), name, shorthand, usage)
124+
}
125+
126+
// IPNetSliceVar defines a []net.IPNet flag with specified name, default value, and usage string.
127+
// The argument p points to a []net.IPNet variable in which to store the value of the flag.
128+
func IPNetSliceVar(p *[]net.IPNet, name string, value []net.IPNet, usage string) {
129+
CommandLine.IPNetSliceVar(p, name, value, usage)
130+
}
131+
132+
// IPNetSliceVarP is like IPNetSliceVar, but accepts a shorthand letter that can be used after a single dash.
133+
func IPNetSliceVarP(p *[]net.IPNet, name, shorthand string, value []net.IPNet, usage string) {
134+
CommandLine.IPNetSliceVarP(p, name, shorthand, value, usage)
135+
}
136+
137+
// IPNetSliceVarS is like IPNetSliceVar, but accepts a shorthand letter that can be used after a single dash, alone.
138+
func IPNetSliceVarS(p *[]net.IPNet, name, shorthand string, value []net.IPNet, usage string) {
139+
CommandLine.IPNetSliceVarS(p, name, shorthand, value, usage)
140+
}
141+
142+
// IPNetSlice defines a []net.IPNet flag with specified name, default value, and usage string.
143+
// The return value is the address of a []net.IPNet variable that stores the value of that flag.
144+
func (f *FlagSet) IPNetSlice(name string, value []net.IPNet, usage string) *[]net.IPNet {
145+
return f.IPNetSliceP(name, "", value, usage)
146+
}
147+
148+
// IPNetSliceP is like IPNetSlice, but accepts a shorthand letter that can be used after a single dash.
149+
func (f *FlagSet) IPNetSliceP(name, shorthand string, value []net.IPNet, usage string) *[]net.IPNet {
150+
p := []net.IPNet{}
151+
f.IPNetSliceVarP(&p, name, shorthand, value, usage)
152+
return &p
153+
}
154+
155+
// IPNetSliceS is like IPNetSlice, but accepts a shorthand letter that can be used after a single dash, alone.
156+
func (f *FlagSet) IPNetSliceS(name, shorthand string, value []net.IPNet, usage string) *[]net.IPNet {
157+
p := []net.IPNet{}
158+
f.IPNetSliceVarS(&p, name, shorthand, value, usage)
159+
return &p
160+
}
161+
162+
// IPNetSlice defines a []net.IPNet flag with specified name, default value, and usage string.
163+
// The return value is the address of a []net.IP variable that stores the value of the flag.
164+
func IPNetSlice(name string, value []net.IPNet, usage string) *[]net.IPNet {
165+
return CommandLine.IPNetSlice(name, value, usage)
166+
}
167+
168+
// IPNetSliceP is like IPNetSlice, but accepts a shorthand letter that can be used after a single dash.
169+
func IPNetSliceP(name, shorthand string, value []net.IPNet, usage string) *[]net.IPNet {
170+
return CommandLine.IPNetSliceP(name, shorthand, value, usage)
171+
}
172+
173+
// IPNetSliceS is like IPNetSlice, but accepts a shorthand letter that can be used after a single dash, alone.
174+
func IPNetSliceS(name, shorthand string, value []net.IPNet, usage string) *[]net.IPNet {
175+
return CommandLine.IPNetSliceS(name, shorthand, value, usage)
176+
}

0 commit comments

Comments
 (0)