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