123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- package flags
- import (
- "strconv"
- )
- type multiTag struct {
- value string
- cache map[string][]string
- }
- func newMultiTag(v string) multiTag {
- return multiTag{
- value: v,
- }
- }
- func (x *multiTag) scan() (map[string][]string, error) {
- v := x.value
- ret := make(map[string][]string)
- // This is mostly copied from reflect.StructTag.Get
- for v != "" {
- i := 0
- // Skip whitespace
- for i < len(v) && v[i] == ' ' {
- i++
- }
- v = v[i:]
- if v == "" {
- break
- }
- // Scan to colon to find key
- i = 0
- for i < len(v) && v[i] != ' ' && v[i] != ':' && v[i] != '"' {
- i++
- }
- if i >= len(v) {
- return nil, newErrorf(ErrTag, "expected `:' after key name, but got end of tag (in `%v`)", x.value)
- }
- if v[i] != ':' {
- return nil, newErrorf(ErrTag, "expected `:' after key name, but got `%v' (in `%v`)", v[i], x.value)
- }
- if i+1 >= len(v) {
- return nil, newErrorf(ErrTag, "expected `\"' to start tag value at end of tag (in `%v`)", x.value)
- }
- if v[i+1] != '"' {
- return nil, newErrorf(ErrTag, "expected `\"' to start tag value, but got `%v' (in `%v`)", v[i+1], x.value)
- }
- name := v[:i]
- v = v[i+1:]
- // Scan quoted string to find value
- i = 1
- for i < len(v) && v[i] != '"' {
- if v[i] == '\n' {
- return nil, newErrorf(ErrTag, "unexpected newline in tag value `%v' (in `%v`)", name, x.value)
- }
- if v[i] == '\\' {
- i++
- }
- i++
- }
- if i >= len(v) {
- return nil, newErrorf(ErrTag, "expected end of tag value `\"' at end of tag (in `%v`)", x.value)
- }
- val, err := strconv.Unquote(v[:i+1])
- if err != nil {
- return nil, newErrorf(ErrTag, "Malformed value of tag `%v:%v` => %v (in `%v`)", name, v[:i+1], err, x.value)
- }
- v = v[i+1:]
- ret[name] = append(ret[name], val)
- }
- return ret, nil
- }
- func (x *multiTag) Parse() error {
- vals, err := x.scan()
- x.cache = vals
- return err
- }
- func (x *multiTag) cached() map[string][]string {
- if x.cache == nil {
- cache, _ := x.scan()
- if cache == nil {
- cache = make(map[string][]string)
- }
- x.cache = cache
- }
- return x.cache
- }
- func (x *multiTag) Get(key string) string {
- c := x.cached()
- if v, ok := c[key]; ok {
- return v[len(v)-1]
- }
- return ""
- }
- func (x *multiTag) GetMany(key string) []string {
- c := x.cached()
- return c[key]
- }
- func (x *multiTag) Set(key string, value string) {
- c := x.cached()
- c[key] = []string{value}
- }
- func (x *multiTag) SetMany(key string, value []string) {
- c := x.cached()
- c[key] = value
- }
|