github.com/neilgarb/delve@v1.9.2-nobreaks/pkg/config/split.go (about) 1 package config 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "reflect" 8 "strconv" 9 "strings" 10 "unicode" 11 ) 12 13 // SplitQuotedFields is like strings.Fields but ignores spaces inside areas surrounded 14 // by the specified quote character. 15 // To specify a single quote use backslash to escape it: \' 16 func SplitQuotedFields(in string, quote rune) []string { 17 type stateEnum int 18 const ( 19 inSpace stateEnum = iota 20 inField 21 inQuote 22 inQuoteEscaped 23 ) 24 state := inSpace 25 r := []string{} 26 var buf bytes.Buffer 27 28 for _, ch := range in { 29 switch state { 30 case inSpace: 31 if ch == quote { 32 state = inQuote 33 } else if !unicode.IsSpace(ch) { 34 buf.WriteRune(ch) 35 state = inField 36 } 37 38 case inField: 39 if ch == quote { 40 state = inQuote 41 } else if unicode.IsSpace(ch) { 42 r = append(r, buf.String()) 43 buf.Reset() 44 } else { 45 buf.WriteRune(ch) 46 } 47 48 case inQuote: 49 if ch == quote { 50 state = inField 51 } else if ch == '\\' { 52 state = inQuoteEscaped 53 } else { 54 buf.WriteRune(ch) 55 } 56 57 case inQuoteEscaped: 58 buf.WriteRune(ch) 59 state = inQuote 60 } 61 } 62 63 if buf.Len() != 0 { 64 r = append(r, buf.String()) 65 } 66 67 return r 68 } 69 70 func ConfigureSetSimple(rest string, cfgname string, field reflect.Value) error { 71 simpleArg := func(typ reflect.Type) (reflect.Value, error) { 72 switch typ.Kind() { 73 case reflect.Int: 74 n, err := strconv.Atoi(rest) 75 if err != nil { 76 return reflect.ValueOf(nil), fmt.Errorf("argument to %q must be a number", cfgname) 77 } 78 if n < 0 { 79 return reflect.ValueOf(nil), fmt.Errorf("argument to %q must be a number greater than zero", cfgname) 80 } 81 return reflect.ValueOf(&n), nil 82 case reflect.Bool: 83 v := rest == "true" 84 return reflect.ValueOf(&v), nil 85 case reflect.String: 86 return reflect.ValueOf(&rest), nil 87 default: 88 return reflect.ValueOf(nil), fmt.Errorf("unsupported type for configuration key %q", cfgname) 89 } 90 } 91 92 if field.Kind() == reflect.Ptr { 93 val, err := simpleArg(field.Type().Elem()) 94 if err != nil { 95 return err 96 } 97 field.Set(val) 98 } else { 99 val, err := simpleArg(field.Type()) 100 if err != nil { 101 return err 102 } 103 field.Set(val.Elem()) 104 } 105 return nil 106 } 107 108 func ConfigureList(w io.Writer, config interface{}, tag string) { 109 it := IterateConfiguration(config, tag) 110 for it.Next() { 111 fieldName, field := it.Field() 112 if fieldName == "" { 113 continue 114 } 115 116 writeField(w, field, fieldName) 117 } 118 } 119 120 func writeField(w io.Writer, field reflect.Value, fieldName string) { 121 switch field.Kind() { 122 case reflect.Interface: 123 switch field := field.Interface().(type) { 124 case string: 125 fmt.Fprintf(w, "%s\t%q\n", fieldName, field) 126 default: 127 fmt.Fprintf(w, "%s\t%v\n", fieldName, field) 128 } 129 case reflect.Ptr: 130 if !field.IsNil() { 131 fmt.Fprintf(w, "%s\t%v\n", fieldName, field.Elem()) 132 } else { 133 fmt.Fprintf(w, "%s\t<not defined>\n", fieldName) 134 } 135 case reflect.String: 136 fmt.Fprintf(w, "%s\t%q\n", fieldName, field) 137 default: 138 fmt.Fprintf(w, "%s\t%v\n", fieldName, field) 139 } 140 } 141 142 type configureIterator struct { 143 cfgValue reflect.Value 144 cfgType reflect.Type 145 i int 146 tag string 147 } 148 149 func IterateConfiguration(conf interface{}, tag string) *configureIterator { 150 cfgValue := reflect.ValueOf(conf).Elem() 151 cfgType := cfgValue.Type() 152 153 return &configureIterator{cfgValue, cfgType, -1, tag} 154 } 155 156 func (it *configureIterator) Next() bool { 157 it.i++ 158 return it.i < it.cfgValue.NumField() 159 } 160 161 func (it *configureIterator) Field() (name string, field reflect.Value) { 162 name = it.cfgType.Field(it.i).Tag.Get(it.tag) 163 if comma := strings.Index(name, ","); comma >= 0 { 164 name = name[:comma] 165 } 166 field = it.cfgValue.Field(it.i) 167 return 168 } 169 170 func ConfigureListByName(conf interface{}, name, tag string) string { 171 if name == "" { 172 return "" 173 } 174 it := IterateConfiguration(conf, tag) 175 for it.Next() { 176 fieldName, field := it.Field() 177 if fieldName == name { 178 var buf bytes.Buffer 179 writeField(&buf, field, fieldName) 180 return buf.String() 181 } 182 } 183 return "" 184 } 185 186 func ConfigureFindFieldByName(conf interface{}, name, tag string) reflect.Value { 187 it := IterateConfiguration(conf, tag) 188 for it.Next() { 189 fieldName, field := it.Field() 190 if fieldName == name { 191 return field 192 } 193 } 194 return reflect.ValueOf(nil) 195 } 196 197 func Split2PartsBySpace(s string) []string { 198 v := strings.SplitN(s, " ", 2) 199 for i := range v { 200 v[i] = strings.TrimSpace(v[i]) 201 } 202 return v 203 }