multitag.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. package flags
  2. import (
  3. "strconv"
  4. )
  5. type multiTag struct {
  6. value string
  7. cache map[string][]string
  8. }
  9. func newMultiTag(v string) multiTag {
  10. return multiTag{
  11. value: v,
  12. }
  13. }
  14. func (x *multiTag) scan() (map[string][]string, error) {
  15. v := x.value
  16. ret := make(map[string][]string)
  17. // This is mostly copied from reflect.StructTag.Get
  18. for v != "" {
  19. i := 0
  20. // Skip whitespace
  21. for i < len(v) && v[i] == ' ' {
  22. i++
  23. }
  24. v = v[i:]
  25. if v == "" {
  26. break
  27. }
  28. // Scan to colon to find key
  29. i = 0
  30. for i < len(v) && v[i] != ' ' && v[i] != ':' && v[i] != '"' {
  31. i++
  32. }
  33. if i >= len(v) {
  34. return nil, newErrorf(ErrTag, "expected `:' after key name, but got end of tag (in `%v`)", x.value)
  35. }
  36. if v[i] != ':' {
  37. return nil, newErrorf(ErrTag, "expected `:' after key name, but got `%v' (in `%v`)", v[i], x.value)
  38. }
  39. if i+1 >= len(v) {
  40. return nil, newErrorf(ErrTag, "expected `\"' to start tag value at end of tag (in `%v`)", x.value)
  41. }
  42. if v[i+1] != '"' {
  43. return nil, newErrorf(ErrTag, "expected `\"' to start tag value, but got `%v' (in `%v`)", v[i+1], x.value)
  44. }
  45. name := v[:i]
  46. v = v[i+1:]
  47. // Scan quoted string to find value
  48. i = 1
  49. for i < len(v) && v[i] != '"' {
  50. if v[i] == '\n' {
  51. return nil, newErrorf(ErrTag, "unexpected newline in tag value `%v' (in `%v`)", name, x.value)
  52. }
  53. if v[i] == '\\' {
  54. i++
  55. }
  56. i++
  57. }
  58. if i >= len(v) {
  59. return nil, newErrorf(ErrTag, "expected end of tag value `\"' at end of tag (in `%v`)", x.value)
  60. }
  61. val, err := strconv.Unquote(v[:i+1])
  62. if err != nil {
  63. return nil, newErrorf(ErrTag, "Malformed value of tag `%v:%v` => %v (in `%v`)", name, v[:i+1], err, x.value)
  64. }
  65. v = v[i+1:]
  66. ret[name] = append(ret[name], val)
  67. }
  68. return ret, nil
  69. }
  70. func (x *multiTag) Parse() error {
  71. vals, err := x.scan()
  72. x.cache = vals
  73. return err
  74. }
  75. func (x *multiTag) cached() map[string][]string {
  76. if x.cache == nil {
  77. cache, _ := x.scan()
  78. if cache == nil {
  79. cache = make(map[string][]string)
  80. }
  81. x.cache = cache
  82. }
  83. return x.cache
  84. }
  85. func (x *multiTag) Get(key string) string {
  86. c := x.cached()
  87. if v, ok := c[key]; ok {
  88. return v[len(v)-1]
  89. }
  90. return ""
  91. }
  92. func (x *multiTag) GetMany(key string) []string {
  93. c := x.cached()
  94. return c[key]
  95. }
  96. func (x *multiTag) Set(key string, value string) {
  97. c := x.cached()
  98. c[key] = []string{value}
  99. }
  100. func (x *multiTag) SetMany(key string, value []string) {
  101. c := x.cached()
  102. c[key] = value
  103. }