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  }