ip_slice.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. package pflag
  2. import (
  3. "fmt"
  4. "io"
  5. "net"
  6. "strings"
  7. )
  8. // -- ipSlice Value
  9. type ipSliceValue struct {
  10. value *[]net.IP
  11. changed bool
  12. }
  13. func newIPSliceValue(val []net.IP, p *[]net.IP) *ipSliceValue {
  14. ipsv := new(ipSliceValue)
  15. ipsv.value = p
  16. *ipsv.value = val
  17. return ipsv
  18. }
  19. // Set converts, and assigns, the comma-separated IP argument string representation as the []net.IP value of this flag.
  20. // If Set is called on a flag that already has a []net.IP assigned, the newly converted values will be appended.
  21. func (s *ipSliceValue) Set(val string) error {
  22. // remove all quote characters
  23. rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "")
  24. // read flag arguments with CSV parser
  25. ipStrSlice, err := readAsCSV(rmQuote.Replace(val))
  26. if err != nil && err != io.EOF {
  27. return err
  28. }
  29. // parse ip values into slice
  30. out := make([]net.IP, 0, len(ipStrSlice))
  31. for _, ipStr := range ipStrSlice {
  32. ip := net.ParseIP(strings.TrimSpace(ipStr))
  33. if ip == nil {
  34. return fmt.Errorf("invalid string being converted to IP address: %s", ipStr)
  35. }
  36. out = append(out, ip)
  37. }
  38. if !s.changed {
  39. *s.value = out
  40. } else {
  41. *s.value = append(*s.value, out...)
  42. }
  43. s.changed = true
  44. return nil
  45. }
  46. // Type returns a string that uniquely represents this flag's type.
  47. func (s *ipSliceValue) Type() string {
  48. return "ipSlice"
  49. }
  50. // String defines a "native" format for this net.IP slice flag value.
  51. func (s *ipSliceValue) String() string {
  52. ipStrSlice := make([]string, len(*s.value))
  53. for i, ip := range *s.value {
  54. ipStrSlice[i] = ip.String()
  55. }
  56. out, _ := writeAsCSV(ipStrSlice)
  57. return "[" + out + "]"
  58. }
  59. func ipSliceConv(val string) (interface{}, error) {
  60. val = strings.Trim(val, "[]")
  61. // Emtpy string would cause a slice with one (empty) entry
  62. if len(val) == 0 {
  63. return []net.IP{}, nil
  64. }
  65. ss := strings.Split(val, ",")
  66. out := make([]net.IP, len(ss))
  67. for i, sval := range ss {
  68. ip := net.ParseIP(strings.TrimSpace(sval))
  69. if ip == nil {
  70. return nil, fmt.Errorf("invalid string being converted to IP address: %s", sval)
  71. }
  72. out[i] = ip
  73. }
  74. return out, nil
  75. }
  76. // GetIPSlice returns the []net.IP value of a flag with the given name
  77. func (f *FlagSet) GetIPSlice(name string) ([]net.IP, error) {
  78. val, err := f.getFlagType(name, "ipSlice", ipSliceConv)
  79. if err != nil {
  80. return []net.IP{}, err
  81. }
  82. return val.([]net.IP), nil
  83. }
  84. // IPSliceVar defines a ipSlice flag with specified name, default value, and usage string.
  85. // The argument p points to a []net.IP variable in which to store the value of the flag.
  86. func (f *FlagSet) IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) {
  87. f.VarP(newIPSliceValue(value, p), name, "", usage)
  88. }
  89. // IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash.
  90. func (f *FlagSet) IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) {
  91. f.VarP(newIPSliceValue(value, p), name, shorthand, usage)
  92. }
  93. // IPSliceVar defines a []net.IP flag with specified name, default value, and usage string.
  94. // The argument p points to a []net.IP variable in which to store the value of the flag.
  95. func IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) {
  96. CommandLine.VarP(newIPSliceValue(value, p), name, "", usage)
  97. }
  98. // IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash.
  99. func IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) {
  100. CommandLine.VarP(newIPSliceValue(value, p), name, shorthand, usage)
  101. }
  102. // IPSlice defines a []net.IP flag with specified name, default value, and usage string.
  103. // The return value is the address of a []net.IP variable that stores the value of that flag.
  104. func (f *FlagSet) IPSlice(name string, value []net.IP, usage string) *[]net.IP {
  105. p := []net.IP{}
  106. f.IPSliceVarP(&p, name, "", value, usage)
  107. return &p
  108. }
  109. // IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash.
  110. func (f *FlagSet) IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP {
  111. p := []net.IP{}
  112. f.IPSliceVarP(&p, name, shorthand, value, usage)
  113. return &p
  114. }
  115. // IPSlice defines a []net.IP flag with specified name, default value, and usage string.
  116. // The return value is the address of a []net.IP variable that stores the value of the flag.
  117. func IPSlice(name string, value []net.IP, usage string) *[]net.IP {
  118. return CommandLine.IPSliceP(name, "", value, usage)
  119. }
  120. // IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash.
  121. func IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP {
  122. return CommandLine.IPSliceP(name, shorthand, value, usage)
  123. }