aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--bool_slice.go147
-rw-r--r--bool_slice_test.go215
-rw-r--r--ip_slice.go148
-rw-r--r--ip_slice_test.go222
-rw-r--r--uint_slice.go126
-rw-r--r--uint_slice_test.go161
7 files changed, 1021 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c3da290
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.idea/*
+
diff --git a/bool_slice.go b/bool_slice.go
new file mode 100644
index 0000000..5af02f1
--- /dev/null
+++ b/bool_slice.go
@@ -0,0 +1,147 @@
+package pflag
+
+import (
+ "io"
+ "strconv"
+ "strings"
+)
+
+// -- boolSlice Value
+type boolSliceValue struct {
+ value *[]bool
+ changed bool
+}
+
+func newBoolSliceValue(val []bool, p *[]bool) *boolSliceValue {
+ bsv := new(boolSliceValue)
+ bsv.value = p
+ *bsv.value = val
+ return bsv
+}
+
+// Set converts, and assigns, the comma-separated boolean argument string representation as the []bool value of this flag.
+// If Set is called on a flag that already has a []bool assigned, the newly converted values will be appended.
+func (s *boolSliceValue) Set(val string) error {
+
+ // remove all quote characters
+ rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "")
+
+ // read flag arguments with CSV parser
+ boolStrSlice, err := readAsCSV(rmQuote.Replace(val))
+ if err != nil && err != io.EOF {
+ return err
+ }
+
+ // parse boolean values into slice
+ out := make([]bool, 0, len(boolStrSlice))
+ for _, boolStr := range boolStrSlice {
+ b, err := strconv.ParseBool(strings.TrimSpace(boolStr))
+ if err != nil {
+ return err
+ }
+ out = append(out, b)
+ }
+
+ if !s.changed {
+ *s.value = out
+ } else {
+ *s.value = append(*s.value, out...)
+ }
+
+ s.changed = true
+
+ return nil
+}
+
+// Type returns a string that uniquely represents this flag's type.
+func (s *boolSliceValue) Type() string {
+ return "boolSlice"
+}
+
+// String defines a "native" format for this boolean slice flag value.
+func (s *boolSliceValue) String() string {
+
+ boolStrSlice := make([]string, len(*s.value))
+ for i, b := range *s.value {
+ boolStrSlice[i] = strconv.FormatBool(b)
+ }
+
+ out, _ := writeAsCSV(boolStrSlice)
+
+ return "[" + out + "]"
+}
+
+func boolSliceConv(val string) (interface{}, error) {
+ val = strings.Trim(val, "[]")
+ // Empty string would cause a slice with one (empty) entry
+ if len(val) == 0 {
+ return []bool{}, nil
+ }
+ ss := strings.Split(val, ",")
+ out := make([]bool, len(ss))
+ for i, t := range ss {
+ var err error
+ out[i], err = strconv.ParseBool(t)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return out, nil
+}
+
+// GetBoolSlice returns the []bool value of a flag with the given name.
+func (f *FlagSet) GetBoolSlice(name string) ([]bool, error) {
+ val, err := f.getFlagType(name, "boolSlice", boolSliceConv)
+ if err != nil {
+ return []bool{}, err
+ }
+ return val.([]bool), nil
+}
+
+// BoolSliceVar defines a boolSlice flag with specified name, default value, and usage string.
+// The argument p points to a []bool variable in which to store the value of the flag.
+func (f *FlagSet) BoolSliceVar(p *[]bool, name string, value []bool, usage string) {
+ f.VarP(newBoolSliceValue(value, p), name, "", usage)
+}
+
+// BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) {
+ f.VarP(newBoolSliceValue(value, p), name, shorthand, usage)
+}
+
+// BoolSliceVar defines a []bool flag with specified name, default value, and usage string.
+// The argument p points to a []bool variable in which to store the value of the flag.
+func BoolSliceVar(p *[]bool, name string, value []bool, usage string) {
+ CommandLine.VarP(newBoolSliceValue(value, p), name, "", usage)
+}
+
+// BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash.
+func BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) {
+ CommandLine.VarP(newBoolSliceValue(value, p), name, shorthand, usage)
+}
+
+// BoolSlice defines a []bool flag with specified name, default value, and usage string.
+// The return value is the address of a []bool variable that stores the value of the flag.
+func (f *FlagSet) BoolSlice(name string, value []bool, usage string) *[]bool {
+ p := []bool{}
+ f.BoolSliceVarP(&p, name, "", value, usage)
+ return &p
+}
+
+// BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool {
+ p := []bool{}
+ f.BoolSliceVarP(&p, name, shorthand, value, usage)
+ return &p
+}
+
+// BoolSlice defines a []bool flag with specified name, default value, and usage string.
+// The return value is the address of a []bool variable that stores the value of the flag.
+func BoolSlice(name string, value []bool, usage string) *[]bool {
+ return CommandLine.BoolSliceP(name, "", value, usage)
+}
+
+// BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash.
+func BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool {
+ return CommandLine.BoolSliceP(name, shorthand, value, usage)
+}
diff --git a/bool_slice_test.go b/bool_slice_test.go
new file mode 100644
index 0000000..b617dd2
--- /dev/null
+++ b/bool_slice_test.go
@@ -0,0 +1,215 @@
+package pflag
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "testing"
+)
+
+func setUpBSFlagSet(bsp *[]bool) *FlagSet {
+ f := NewFlagSet("test", ContinueOnError)
+ f.BoolSliceVar(bsp, "bs", []bool{}, "Command separated list!")
+ return f
+}
+
+func setUpBSFlagSetWithDefault(bsp *[]bool) *FlagSet {
+ f := NewFlagSet("test", ContinueOnError)
+ f.BoolSliceVar(bsp, "bs", []bool{false, true}, "Command separated list!")
+ return f
+}
+
+func TestEmptyBS(t *testing.T) {
+ var bs []bool
+ f := setUpBSFlagSet(&bs)
+ err := f.Parse([]string{})
+ if err != nil {
+ t.Fatal("expected no error; got", err)
+ }
+
+ getBS, err := f.GetBoolSlice("bs")
+ if err != nil {
+ t.Fatal("got an error from GetBoolSlice():", err)
+ }
+ if len(getBS) != 0 {
+ t.Fatalf("got bs %v with len=%d but expected length=0", getBS, len(getBS))
+ }
+}
+
+func TestBS(t *testing.T) {
+ var bs []bool
+ f := setUpBSFlagSet(&bs)
+
+ vals := []string{"1", "F", "TRUE", "0"}
+ arg := fmt.Sprintf("--bs=%s", strings.Join(vals, ","))
+ err := f.Parse([]string{arg})
+ if err != nil {
+ t.Fatal("expected no error; got", err)
+ }
+ for i, v := range bs {
+ b, err := strconv.ParseBool(vals[i])
+ if err != nil {
+ t.Fatalf("got error: %v", err)
+ }
+ if b != v {
+ t.Fatalf("expected is[%d] to be %s but got: %t", i, vals[i], v)
+ }
+ }
+ getBS, err := f.GetBoolSlice("bs")
+ if err != nil {
+ t.Fatalf("got error: %v", err)
+ }
+ for i, v := range getBS {
+ b, err := strconv.ParseBool(vals[i])
+ if err != nil {
+ t.Fatalf("got error: %v", err)
+ }
+ if b != v {
+ t.Fatalf("expected bs[%d] to be %s but got: %t from GetBoolSlice", i, vals[i], v)
+ }
+ }
+}
+
+func TestBSDefault(t *testing.T) {
+ var bs []bool
+ f := setUpBSFlagSetWithDefault(&bs)
+
+ vals := []string{"false", "T"}
+
+ err := f.Parse([]string{})
+ if err != nil {
+ t.Fatal("expected no error; got", err)
+ }
+ for i, v := range bs {
+ b, err := strconv.ParseBool(vals[i])
+ if err != nil {
+ t.Fatalf("got error: %v", err)
+ }
+ if b != v {
+ t.Fatalf("expected bs[%d] to be %t from GetBoolSlice but got: %t", i, b, v)
+ }
+ }
+
+ getBS, err := f.GetBoolSlice("bs")
+ if err != nil {
+ t.Fatal("got an error from GetBoolSlice():", err)
+ }
+ for i, v := range getBS {
+ b, err := strconv.ParseBool(vals[i])
+ if err != nil {
+ t.Fatal("got an error from GetBoolSlice():", err)
+ }
+ if b != v {
+ t.Fatalf("expected bs[%d] to be %t from GetBoolSlice but got: %t", i, b, v)
+ }
+ }
+}
+
+func TestBSWithDefault(t *testing.T) {
+ var bs []bool
+ f := setUpBSFlagSetWithDefault(&bs)
+
+ vals := []string{"FALSE", "1"}
+ arg := fmt.Sprintf("--bs=%s", strings.Join(vals, ","))
+ err := f.Parse([]string{arg})
+ if err != nil {
+ t.Fatal("expected no error; got", err)
+ }
+ for i, v := range bs {
+ b, err := strconv.ParseBool(vals[i])
+ if err != nil {
+ t.Fatalf("got error: %v", err)
+ }
+ if b != v {
+ t.Fatalf("expected bs[%d] to be %t but got: %t", i, b, v)
+ }
+ }
+
+ getBS, err := f.GetBoolSlice("bs")
+ if err != nil {
+ t.Fatal("got an error from GetBoolSlice():", err)
+ }
+ for i, v := range getBS {
+ b, err := strconv.ParseBool(vals[i])
+ if err != nil {
+ t.Fatalf("got error: %v", err)
+ }
+ if b != v {
+ t.Fatalf("expected bs[%d] to be %t from GetBoolSlice but got: %t", i, b, v)
+ }
+ }
+}
+
+func TestBSCalledTwice(t *testing.T) {
+ var bs []bool
+ f := setUpBSFlagSet(&bs)
+
+ in := []string{"T,F", "T"}
+ expected := []bool{true, false, true}
+ argfmt := "--bs=%s"
+ arg1 := fmt.Sprintf(argfmt, in[0])
+ arg2 := fmt.Sprintf(argfmt, in[1])
+ err := f.Parse([]string{arg1, arg2})
+ if err != nil {
+ t.Fatal("expected no error; got", err)
+ }
+ for i, v := range bs {
+ if expected[i] != v {
+ t.Fatalf("expected bs[%d] to be %t but got %t", i, expected[i], v)
+ }
+ }
+}
+
+func TestBSBadQuoting(t *testing.T) {
+
+ tests := []struct {
+ Want []bool
+ FlagArg []string
+ }{
+ {
+ Want: []bool{true, false, true},
+ FlagArg: []string{"1", "0", "true"},
+ },
+ {
+ Want: []bool{true, false},
+ FlagArg: []string{"True", "F"},
+ },
+ {
+ Want: []bool{true, false},
+ FlagArg: []string{"T", "0"},
+ },
+ {
+ Want: []bool{true, false},
+ FlagArg: []string{"1", "0"},
+ },
+ {
+ Want: []bool{true, false, false},
+ FlagArg: []string{"true,false", "false"},
+ },
+ {
+ Want: []bool{true, false, false, true, false, true, false},
+ FlagArg: []string{`"true,false,false,1,0, T"`, " false "},
+ },
+ {
+ Want: []bool{false, false, true, false, true, false, true},
+ FlagArg: []string{`"0, False, T,false , true,F"`, "true"},
+ },
+ }
+
+ for i, test := range tests {
+
+ var bs []bool
+ f := setUpBSFlagSet(&bs)
+
+ if err := f.Parse([]string{fmt.Sprintf("--bs=%s", strings.Join(test.FlagArg, ","))}); err != nil {
+ t.Fatalf("flag parsing failed with error: %s\nparsing:\t%#v\nwant:\t\t%#v",
+ err, test.FlagArg, test.Want[i])
+ }
+
+ for j, b := range bs {
+ if b != test.Want[j] {
+ t.Fatalf("bad value parsed for test %d on bool %d:\nwant:\t%t\ngot:\t%t", i, j, test.Want[j], b)
+ }
+ }
+ }
+}
diff --git a/ip_slice.go b/ip_slice.go
new file mode 100644
index 0000000..7dd196f
--- /dev/null
+++ b/ip_slice.go
@@ -0,0 +1,148 @@
+package pflag
+
+import (
+ "fmt"
+ "io"
+ "net"
+ "strings"
+)
+
+// -- ipSlice Value
+type ipSliceValue struct {
+ value *[]net.IP
+ changed bool
+}
+
+func newIPSliceValue(val []net.IP, p *[]net.IP) *ipSliceValue {
+ ipsv := new(ipSliceValue)
+ ipsv.value = p
+ *ipsv.value = val
+ return ipsv
+}
+
+// Set converts, and assigns, the comma-separated IP argument string representation as the []net.IP value of this flag.
+// If Set is called on a flag that already has a []net.IP assigned, the newly converted values will be appended.
+func (s *ipSliceValue) Set(val string) error {
+
+ // remove all quote characters
+ rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "")
+
+ // read flag arguments with CSV parser
+ ipStrSlice, err := readAsCSV(rmQuote.Replace(val))
+ if err != nil && err != io.EOF {
+ return err
+ }
+
+ // parse ip values into slice
+ out := make([]net.IP, 0, len(ipStrSlice))
+ for _, ipStr := range ipStrSlice {
+ ip := net.ParseIP(strings.TrimSpace(ipStr))
+ if ip == nil {
+ return fmt.Errorf("invalid string being converted to IP address: %s", ipStr)
+ }
+ out = append(out, ip)
+ }
+
+ if !s.changed {
+ *s.value = out
+ } else {
+ *s.value = append(*s.value, out...)
+ }
+
+ s.changed = true
+
+ return nil
+}
+
+// Type returns a string that uniquely represents this flag's type.
+func (s *ipSliceValue) Type() string {
+ return "ipSlice"
+}
+
+// String defines a "native" format for this net.IP slice flag value.
+func (s *ipSliceValue) String() string {
+
+ ipStrSlice := make([]string, len(*s.value))
+ for i, ip := range *s.value {
+ ipStrSlice[i] = ip.String()
+ }
+
+ out, _ := writeAsCSV(ipStrSlice)
+
+ return "[" + out + "]"
+}
+
+func ipSliceConv(val string) (interface{}, error) {
+ val = strings.Trim(val, "[]")
+ // Emtpy string would cause a slice with one (empty) entry
+ if len(val) == 0 {
+ return []net.IP{}, nil
+ }
+ ss := strings.Split(val, ",")
+ out := make([]net.IP, len(ss))
+ for i, sval := range ss {
+ ip := net.ParseIP(strings.TrimSpace(sval))
+ if ip == nil {
+ return nil, fmt.Errorf("invalid string being converted to IP address: %s", sval)
+ }
+ out[i] = ip
+ }
+ return out, nil
+}
+
+// GetIPSlice returns the []net.IP value of a flag with the given name
+func (f *FlagSet) GetIPSlice(name string) ([]net.IP, error) {
+ val, err := f.getFlagType(name, "ipSlice", ipSliceConv)
+ if err != nil {
+ return []net.IP{}, err
+ }
+ return val.([]net.IP), nil
+}
+
+// IPSliceVar defines a ipSlice flag with specified name, default value, and usage string.
+// The argument p points to a []net.IP variable in which to store the value of the flag.
+func (f *FlagSet) IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) {
+ f.VarP(newIPSliceValue(value, p), name, "", usage)
+}
+
+// IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) {
+ f.VarP(newIPSliceValue(value, p), name, shorthand, usage)
+}
+
+// IPSliceVar defines a []net.IP flag with specified name, default value, and usage string.
+// The argument p points to a []net.IP variable in which to store the value of the flag.
+func IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) {
+ CommandLine.VarP(newIPSliceValue(value, p), name, "", usage)
+}
+
+// IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash.
+func IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) {
+ CommandLine.VarP(newIPSliceValue(value, p), name, shorthand, usage)
+}
+
+// IPSlice defines a []net.IP flag with specified name, default value, and usage string.
+// The return value is the address of a []net.IP variable that stores the value of that flag.
+func (f *FlagSet) IPSlice(name string, value []net.IP, usage string) *[]net.IP {
+ p := []net.IP{}
+ f.IPSliceVarP(&p, name, "", value, usage)
+ return &p
+}
+
+// IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP {
+ p := []net.IP{}
+ f.IPSliceVarP(&p, name, shorthand, value, usage)
+ return &p
+}
+
+// IPSlice defines a []net.IP flag with specified name, default value, and usage string.
+// The return value is the address of a []net.IP variable that stores the value of the flag.
+func IPSlice(name string, value []net.IP, usage string) *[]net.IP {
+ return CommandLine.IPSliceP(name, "", value, usage)
+}
+
+// IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash.
+func IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP {
+ return CommandLine.IPSliceP(name, shorthand, value, usage)
+}
diff --git a/ip_slice_test.go b/ip_slice_test.go
new file mode 100644
index 0000000..b0c681c
--- /dev/null
+++ b/ip_slice_test.go
@@ -0,0 +1,222 @@
+package pflag
+
+import (
+ "fmt"
+ "net"
+ "strings"
+ "testing"
+)
+
+func setUpIPSFlagSet(ipsp *[]net.IP) *FlagSet {
+ f := NewFlagSet("test", ContinueOnError)
+ f.IPSliceVar(ipsp, "ips", []net.IP{}, "Command separated list!")
+ return f
+}
+
+func setUpIPSFlagSetWithDefault(ipsp *[]net.IP) *FlagSet {
+ f := NewFlagSet("test", ContinueOnError)
+ f.IPSliceVar(ipsp, "ips",
+ []net.IP{
+ net.ParseIP("192.168.1.1"),
+ net.ParseIP("0:0:0:0:0:0:0:1"),
+ },
+ "Command separated list!")
+ return f
+}
+
+func TestEmptyIP(t *testing.T) {
+ var ips []net.IP
+ f := setUpIPSFlagSet(&ips)
+ err := f.Parse([]string{})
+ if err != nil {
+ t.Fatal("expected no error; got", err)
+ }
+
+ getIPS, err := f.GetIPSlice("ips")
+ if err != nil {
+ t.Fatal("got an error from GetIPSlice():", err)
+ }
+ if len(getIPS) != 0 {
+ t.Fatalf("got ips %v with len=%d but expected length=0", getIPS, len(getIPS))
+ }
+}
+
+func TestIPS(t *testing.T) {
+ var ips []net.IP
+ f := setUpIPSFlagSet(&ips)
+
+ vals := []string{"192.168.1.1", "10.0.0.1", "0:0:0:0:0:0:0:2"}
+ arg := fmt.Sprintf("--ips=%s", strings.Join(vals, ","))
+ err := f.Parse([]string{arg})
+ if err != nil {
+ t.Fatal("expected no error; got", err)
+ }
+ for i, v := range ips {
+ if ip := net.ParseIP(vals[i]); ip == nil {
+ t.Fatalf("invalid string being converted to IP address: %s", vals[i])
+ } else if !ip.Equal(v) {
+ t.Fatalf("expected ips[%d] to be %s but got: %s from GetIPSlice", i, vals[i], v)
+ }
+ }
+}
+
+func TestIPSDefault(t *testing.T) {
+ var ips []net.IP
+ f := setUpIPSFlagSetWithDefault(&ips)
+
+ vals := []string{"192.168.1.1", "0:0:0:0:0:0:0:1"}
+ err := f.Parse([]string{})
+ if err != nil {
+ t.Fatal("expected no error; got", err)
+ }
+ for i, v := range ips {
+ if ip := net.ParseIP(vals[i]); ip == nil {
+ t.Fatalf("invalid string being converted to IP address: %s", vals[i])
+ } else if !ip.Equal(v) {
+ t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v)
+ }
+ }
+
+ getIPS, err := f.GetIPSlice("ips")
+ if err != nil {
+ t.Fatal("got an error from GetIPSlice")
+ }
+ for i, v := range getIPS {
+ if ip := net.ParseIP(vals[i]); ip == nil {
+ t.Fatalf("invalid string being converted to IP address: %s", vals[i])
+ } else if !ip.Equal(v) {
+ t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v)
+ }
+ }
+}
+
+func TestIPSWithDefault(t *testing.T) {
+ var ips []net.IP
+ f := setUpIPSFlagSetWithDefault(&ips)
+
+ vals := []string{"192.168.1.1", "0:0:0:0:0:0:0:1"}
+ arg := fmt.Sprintf("--ips=%s", strings.Join(vals, ","))
+ err := f.Parse([]string{arg})
+ if err != nil {
+ t.Fatal("expected no error; got", err)
+ }
+ for i, v := range ips {
+ if ip := net.ParseIP(vals[i]); ip == nil {
+ t.Fatalf("invalid string being converted to IP address: %s", vals[i])
+ } else if !ip.Equal(v) {
+ t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v)
+ }
+ }
+
+ getIPS, err := f.GetIPSlice("ips")
+ if err != nil {
+ t.Fatal("got an error from GetIPSlice")
+ }
+ for i, v := range getIPS {
+ if ip := net.ParseIP(vals[i]); ip == nil {
+ t.Fatalf("invalid string being converted to IP address: %s", vals[i])
+ } else if !ip.Equal(v) {
+ t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v)
+ }
+ }
+}
+
+func TestIPSCalledTwice(t *testing.T) {
+ var ips []net.IP
+ f := setUpIPSFlagSet(&ips)
+
+ in := []string{"192.168.1.2,0:0:0:0:0:0:0:1", "10.0.0.1"}
+ expected := []net.IP{net.ParseIP("192.168.1.2"), net.ParseIP("0:0:0:0:0:0:0:1"), net.ParseIP("10.0.0.1")}
+ argfmt := "ips=%s"
+ arg1 := fmt.Sprintf(argfmt, in[0])
+ arg2 := fmt.Sprintf(argfmt, in[1])
+ err := f.Parse([]string{arg1, arg2})
+ if err != nil {
+ t.Fatal("expected no error; got", err)
+ }
+ for i, v := range ips {
+ if !expected[i].Equal(v) {
+ t.Fatalf("expected ips[%d] to be %s but got: %s", i, expected[i], v)
+ }
+ }
+}
+
+func TestIPSBadQuoting(t *testing.T) {
+
+ tests := []struct {
+ Want []net.IP
+ FlagArg []string
+ }{
+ {
+ Want: []net.IP{
+ net.ParseIP("a4ab:61d:f03e:5d7d:fad7:d4c2:a1a5:568"),
+ net.ParseIP("203.107.49.208"),
+ net.ParseIP("14.57.204.90"),
+ },
+ FlagArg: []string{
+ "a4ab:61d:f03e:5d7d:fad7:d4c2:a1a5:568",
+ "203.107.49.208",
+ "14.57.204.90",
+ },
+ },
+ {
+ Want: []net.IP{
+ net.ParseIP("204.228.73.195"),
+ net.ParseIP("86.141.15.94"),
+ },
+ FlagArg: []string{
+ "204.228.73.195",
+ "86.141.15.94",
+ },
+ },
+ {
+ Want: []net.IP{
+ net.ParseIP("c70c:db36:3001:890f:c6ea:3f9b:7a39:cc3f"),
+ net.ParseIP("4d17:1d6e:e699:bd7a:88c5:5e7e:ac6a:4472"),
+ },
+ FlagArg: []string{
+ "c70c:db36:3001:890f:c6ea:3f9b:7a39:cc3f",
+ "4d17:1d6e:e699:bd7a:88c5:5e7e:ac6a:4472",
+ },
+ },
+ {
+ Want: []net.IP{
+ net.ParseIP("5170:f971:cfac:7be3:512a:af37:952c:bc33"),
+ net.ParseIP("93.21.145.140"),
+ net.ParseIP("2cac:61d3:c5ff:6caf:73e0:1b1a:c336:c1ca"),
+ },
+ FlagArg: []string{
+ " 5170:f971:cfac:7be3:512a:af37:952c:bc33 , 93.21.145.140 ",
+ "2cac:61d3:c5ff:6caf:73e0:1b1a:c336:c1ca",
+ },
+ },
+ {
+ Want: []net.IP{
+ net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"),
+ net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"),
+ net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"),
+ net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"),
+ },
+ FlagArg: []string{
+ `"2e5e:66b2:6441:848:5b74:76ea:574c:3a7b, 2e5e:66b2:6441:848:5b74:76ea:574c:3a7b,2e5e:66b2:6441:848:5b74:76ea:574c:3a7b "`,
+ " 2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"},
+ },
+ }
+
+ for i, test := range tests {
+
+ var ips []net.IP
+ f := setUpIPSFlagSet(&ips)
+
+ if err := f.Parse([]string{fmt.Sprintf("--ips=%s", strings.Join(test.FlagArg, ","))}); err != nil {
+ t.Fatalf("flag parsing failed with error: %s\nparsing:\t%#v\nwant:\t\t%s",
+ err, test.FlagArg, test.Want[i])
+ }
+
+ for j, b := range ips {
+ if !b.Equal(test.Want[j]) {
+ t.Fatalf("bad value parsed for test %d on net.IP %d:\nwant:\t%s\ngot:\t%s", i, j, test.Want[j], b)
+ }
+ }
+ }
+}
diff --git a/uint_slice.go b/uint_slice.go
new file mode 100644
index 0000000..edd94c6
--- /dev/null
+++ b/uint_slice.go
@@ -0,0 +1,126 @@
+package pflag
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// -- uintSlice Value
+type uintSliceValue struct {
+ value *[]uint
+ changed bool
+}
+
+func newUintSliceValue(val []uint, p *[]uint) *uintSliceValue {
+ uisv := new(uintSliceValue)
+ uisv.value = p
+ *uisv.value = val
+ return uisv
+}
+
+func (s *uintSliceValue) Set(val string) error {
+ ss := strings.Split(val, ",")
+ out := make([]uint, len(ss))
+ for i, d := range ss {
+ u, err := strconv.ParseUint(d, 10, 0)
+ if err != nil {
+ return err
+ }
+ out[i] = uint(u)
+ }
+ if !s.changed {
+ *s.value = out
+ } else {
+ *s.value = append(*s.value, out...)
+ }
+ s.changed = true
+ return nil
+}
+
+func (s *uintSliceValue) Type() string {
+ return "uintSlice"
+}
+
+func (s *uintSliceValue) String() string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = fmt.Sprintf("%d", d)
+ }
+ return "[" + strings.Join(out, ",") + "]"
+}
+
+func uintSliceConv(val string) (interface{}, error) {
+ val = strings.Trim(val, "[]")
+ // Empty string would cause a slice with one (empty) entry
+ if len(val) == 0 {
+ return []uint{}, nil
+ }
+ ss := strings.Split(val, ",")
+ out := make([]uint, len(ss))
+ for i, d := range ss {
+ u, err := strconv.ParseUint(d, 10, 0)
+ if err != nil {
+ return nil, err
+ }
+ out[i] = uint(u)
+ }
+ return out, nil
+}
+
+// GetUintSlice returns the []uint value of a flag with the given name.
+func (f *FlagSet) GetUintSlice(name string) ([]uint, error) {
+ val, err := f.getFlagType(name, "uintSlice", uintSliceConv)
+ if err != nil {
+ return []uint{}, err
+ }
+ return val.([]uint), nil
+}
+
+// UintSliceVar defines a uintSlice flag with specified name, default value, and usage string.
+// The argument p points to a []uint variable in which to store the value of the flag.
+func (f *FlagSet) UintSliceVar(p *[]uint, name string, value []uint, usage string) {
+ f.VarP(newUintSliceValue(value, p), name, "", usage)
+}
+
+// UintSliceVarP is like UintSliceVar, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) {
+ f.VarP(newUintSliceValue(value, p), name, shorthand, usage)
+}
+
+// UintSliceVar defines a uint[] flag with specified name, default value, and usage string.
+// The argument p points to a uint[] variable in which to store the value of the flag.
+func UintSliceVar(p *[]uint, name string, value []uint, usage string) {
+ CommandLine.VarP(newUintSliceValue(value, p), name, "", usage)
+}
+
+// UintSliceVarP is like the UintSliceVar, but accepts a shorthand letter that can be used after a single dash.
+func UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) {
+ CommandLine.VarP(newUintSliceValue(value, p), name, shorthand, usage)
+}
+
+// UintSlice defines a []uint flag with specified name, default value, and usage string.
+// The return value is the address of a []uint variable that stores the value of the flag.
+func (f *FlagSet) UintSlice(name string, value []uint, usage string) *[]uint {
+ p := []uint{}
+ f.UintSliceVarP(&p, name, "", value, usage)
+ return &p
+}
+
+// UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) UintSliceP(name, shorthand string, value []uint, usage string) *[]uint {
+ p := []uint{}
+ f.UintSliceVarP(&p, name, shorthand, value, usage)
+ return &p
+}
+
+// UintSlice defines a []uint flag with specified name, default value, and usage string.
+// The return value is the address of a []uint variable that stores the value of the flag.
+func UintSlice(name string, value []uint, usage string) *[]uint {
+ return CommandLine.UintSliceP(name, "", value, usage)
+}
+
+// UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash.
+func UintSliceP(name, shorthand string, value []uint, usage string) *[]uint {
+ return CommandLine.UintSliceP(name, shorthand, value, usage)
+}
diff --git a/uint_slice_test.go b/uint_slice_test.go
new file mode 100644
index 0000000..db1a19d
--- /dev/null
+++ b/uint_slice_test.go
@@ -0,0 +1,161 @@
+package pflag
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "testing"
+)
+
+func setUpUISFlagSet(uisp *[]uint) *FlagSet {
+ f := NewFlagSet("test", ContinueOnError)
+ f.UintSliceVar(uisp, "uis", []uint{}, "Command separated list!")
+ return f
+}
+
+func setUpUISFlagSetWithDefault(uisp *[]uint) *FlagSet {
+ f := NewFlagSet("test", ContinueOnError)
+ f.UintSliceVar(uisp, "uis", []uint{0, 1}, "Command separated list!")
+ return f
+}
+
+func TestEmptyUIS(t *testing.T) {
+ var uis []uint
+ f := setUpUISFlagSet(&uis)
+ err := f.Parse([]string{})
+ if err != nil {
+ t.Fatal("expected no error; got", err)
+ }
+
+ getUIS, err := f.GetUintSlice("uis")
+ if err != nil {
+ t.Fatal("got an error from GetUintSlice():", err)
+ }
+ if len(getUIS) != 0 {
+ t.Fatalf("got is %v with len=%d but expected length=0", getUIS, len(getUIS))
+ }
+}
+
+func TestUIS(t *testing.T) {
+ var uis []uint
+ f := setUpUISFlagSet(&uis)
+
+ vals := []string{"1", "2", "4", "3"}
+ arg := fmt.Sprintf("--uis=%s", strings.Join(vals, ","))
+ err := f.Parse([]string{arg})
+ if err != nil {
+ t.Fatal("expected no error; got", err)
+ }
+ for i, v := range uis {
+ u, err := strconv.ParseUint(vals[i], 10, 0)
+ if err != nil {
+ t.Fatalf("got error: %v", err)
+ }
+ if uint(u) != v {
+ t.Fatalf("expected uis[%d] to be %s but got %d", i, vals[i], v)
+ }
+ }
+ getUIS, err := f.GetUintSlice("uis")
+ if err != nil {
+ t.Fatalf("got error: %v", err)
+ }
+ for i, v := range getUIS {
+ u, err := strconv.ParseUint(vals[i], 10, 0)
+ if err != nil {
+ t.Fatalf("got error: %v", err)
+ }
+ if uint(u) != v {
+ t.Fatalf("expected uis[%d] to be %s but got: %d from GetUintSlice", i, vals[i], v)
+ }
+ }
+}
+
+func TestUISDefault(t *testing.T) {
+ var uis []uint
+ f := setUpUISFlagSetWithDefault(&uis)
+
+ vals := []string{"0", "1"}
+
+ err := f.Parse([]string{})
+ if err != nil {
+ t.Fatal("expected no error; got", err)
+ }
+ for i, v := range uis {
+ u, err := strconv.ParseUint(vals[i], 10, 0)
+ if err != nil {
+ t.Fatalf("got error: %v", err)
+ }
+ if uint(u) != v {
+ t.Fatalf("expect uis[%d] to be %d but got: %d", i, u, v)
+ }
+ }
+
+ getUIS, err := f.GetUintSlice("uis")
+ if err != nil {
+ t.Fatal("got an error from GetUintSlice():", err)
+ }
+ for i, v := range getUIS {
+ u, err := strconv.ParseUint(vals[i], 10, 0)
+ if err != nil {
+ t.Fatal("got an error from GetIntSlice():", err)
+ }
+ if uint(u) != v {
+ t.Fatalf("expected uis[%d] to be %d from GetUintSlice but got: %d", i, u, v)
+ }
+ }
+}
+
+func TestUISWithDefault(t *testing.T) {
+ var uis []uint
+ f := setUpUISFlagSetWithDefault(&uis)
+
+ vals := []string{"1", "2"}
+ arg := fmt.Sprintf("--uis=%s", strings.Join(vals, ","))
+ err := f.Parse([]string{arg})
+ if err != nil {
+ t.Fatal("expected no error; got", err)
+ }
+ for i, v := range uis {
+ u, err := strconv.ParseUint(vals[i], 10, 0)
+ if err != nil {
+ t.Fatalf("got error: %v", err)
+ }
+ if uint(u) != v {
+ t.Fatalf("expected uis[%d] to be %d from GetUintSlice but got: %d", i, u, v)
+ }
+ }
+
+ getUIS, err := f.GetUintSlice("uis")
+ if err != nil {
+ t.Fatal("got an error from GetUintSlice():", err)
+ }
+ for i, v := range getUIS {
+ u, err := strconv.ParseUint(vals[i], 10, 0)
+ if err != nil {
+ t.Fatalf("got error: %v", err)
+ }
+ if uint(u) != v {
+ t.Fatalf("expected uis[%d] to be %d from GetUintSlice but got: %d", i, u, v)
+ }
+ }
+}
+
+func TestUISCalledTwice(t *testing.T) {
+ var uis []uint
+ f := setUpUISFlagSet(&uis)
+
+ in := []string{"1,2", "3"}
+ expected := []int{1, 2, 3}
+ argfmt := "--uis=%s"
+ arg1 := fmt.Sprintf(argfmt, in[0])
+ arg2 := fmt.Sprintf(argfmt, in[1])
+ err := f.Parse([]string{arg1, arg2})
+ if err != nil {
+ t.Fatal("expected no error; got", err)
+ }
+ for i, v := range uis {
+ if uint(expected[i]) != v {
+ t.Fatalf("expected uis[%d] to be %d but got: %d", i, expected[i], v)
+ }
+ }
+}