github.com/richardwilkes/toolbox@v1.121.0/cmdline/values.go (about) 1 // Copyright (c) 2016-2024 by Richard A. Wilkes. All rights reserved. 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, version 2.0. If a copy of the MPL was not distributed with 5 // this file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 // 7 // This Source Code Form is "Incompatible With Secondary Licenses", as 8 // defined by the Mozilla Public License, version 2.0. 9 10 package cmdline 11 12 import ( 13 "fmt" 14 "reflect" 15 "strconv" 16 "strings" 17 "time" 18 19 "github.com/richardwilkes/toolbox/errs" 20 ) 21 22 var _ Value = &GeneralValue{} 23 24 // GeneralValue holds a general option value. Valid value types are: *bool, *int, *int8, *int16, *int32, *int64, *uint, 25 // *uint8, *uint16, *uint32, *uint64, *float32, *float64, *string, *time.Duration, *[]bool, *[]uint8, *[]uint16, 26 // *[]uint32, *[]uint64, *[]int8, *[]int16, *[]int32, *[]int64, *[]string, *[]time.Duration 27 type GeneralValue struct { 28 Value any 29 } 30 31 // Set implements Value 32 func (v *GeneralValue) Set(str string) error { 33 var err error 34 var signedValue int64 35 var unsignedValue uint64 36 var floatValue float64 37 switch value := v.Value.(type) { 38 case *bool: 39 if *value, err = strconv.ParseBool(str); err != nil { 40 return errs.Wrap(err) 41 } 42 case *int: 43 if signedValue, err = strconv.ParseInt(str, 0, 64); err != nil { 44 return errs.Wrap(err) 45 } 46 *value = int(signedValue) 47 case *int8: 48 if signedValue, err = strconv.ParseInt(str, 0, 8); err != nil { 49 return errs.Wrap(err) 50 } 51 *value = int8(signedValue) 52 case *int16: 53 if signedValue, err = strconv.ParseInt(str, 0, 16); err != nil { 54 return errs.Wrap(err) 55 } 56 *value = int16(signedValue) 57 case *int32: 58 if signedValue, err = strconv.ParseInt(str, 0, 32); err != nil { 59 return errs.Wrap(err) 60 } 61 *value = int32(signedValue) 62 case *int64: 63 if *value, err = strconv.ParseInt(str, 0, 64); err != nil { 64 return errs.Wrap(err) 65 } 66 case *uint: 67 if unsignedValue, err = strconv.ParseUint(str, 0, 64); err != nil { 68 return errs.Wrap(err) 69 } 70 *value = uint(unsignedValue) 71 case *uint8: 72 if unsignedValue, err = strconv.ParseUint(str, 0, 8); err != nil { 73 return errs.Wrap(err) 74 } 75 *value = uint8(unsignedValue) 76 case *uint16: 77 if unsignedValue, err = strconv.ParseUint(str, 0, 16); err != nil { 78 return errs.Wrap(err) 79 } 80 *value = uint16(unsignedValue) 81 case *uint32: 82 if unsignedValue, err = strconv.ParseUint(str, 0, 32); err != nil { 83 return errs.Wrap(err) 84 } 85 *value = uint32(unsignedValue) 86 case *uint64: 87 if *value, err = strconv.ParseUint(str, 0, 64); err != nil { 88 return errs.Wrap(err) 89 } 90 case *float32: 91 if floatValue, err = strconv.ParseFloat(str, 32); err != nil { 92 return errs.Wrap(err) 93 } 94 *value = float32(floatValue) 95 case *float64: 96 if *value, err = strconv.ParseFloat(str, 64); err != nil { 97 return errs.Wrap(err) 98 } 99 case *string: 100 *value = str 101 case *time.Duration: 102 if *value, err = time.ParseDuration(str); err != nil { 103 return errs.Wrap(err) 104 } 105 case *[]bool: 106 var b bool 107 if b, err = strconv.ParseBool(str); err != nil { 108 return errs.Wrap(err) 109 } 110 *value = append(*value, b) 111 case *[]int: 112 if signedValue, err = strconv.ParseInt(str, 0, 64); err != nil { 113 return errs.Wrap(err) 114 } 115 *value = append(*value, int(signedValue)) 116 case *[]int8: 117 if signedValue, err = strconv.ParseInt(str, 0, 8); err != nil { 118 return errs.Wrap(err) 119 } 120 *value = append(*value, int8(signedValue)) 121 case *[]int16: 122 if signedValue, err = strconv.ParseInt(str, 0, 16); err != nil { 123 return errs.Wrap(err) 124 } 125 *value = append(*value, int16(signedValue)) 126 case *[]int32: 127 if signedValue, err = strconv.ParseInt(str, 0, 32); err != nil { 128 return errs.Wrap(err) 129 } 130 *value = append(*value, int32(signedValue)) 131 case *[]int64: 132 if signedValue, err = strconv.ParseInt(str, 0, 64); err != nil { 133 return errs.Wrap(err) 134 } 135 *value = append(*value, signedValue) 136 case *[]uint: 137 if unsignedValue, err = strconv.ParseUint(str, 0, 64); err != nil { 138 return errs.Wrap(err) 139 } 140 *value = append(*value, uint(unsignedValue)) 141 case *[]uint8: 142 if unsignedValue, err = strconv.ParseUint(str, 0, 8); err != nil { 143 return errs.Wrap(err) 144 } 145 *value = append(*value, uint8(unsignedValue)) 146 case *[]uint16: 147 if unsignedValue, err = strconv.ParseUint(str, 0, 16); err != nil { 148 return errs.Wrap(err) 149 } 150 *value = append(*value, uint16(unsignedValue)) 151 case *[]uint32: 152 if unsignedValue, err = strconv.ParseUint(str, 0, 32); err != nil { 153 return errs.Wrap(err) 154 } 155 *value = append(*value, uint32(unsignedValue)) 156 case *[]uint64: 157 if unsignedValue, err = strconv.ParseUint(str, 0, 64); err != nil { 158 return errs.Wrap(err) 159 } 160 *value = append(*value, unsignedValue) 161 case *[]string: 162 *value = append(*value, str) 163 case *[]time.Duration: 164 var d time.Duration 165 if d, err = time.ParseDuration(str); err != nil { 166 return errs.Wrap(err) 167 } 168 *value = append(*value, d) 169 default: 170 return errs.Newf("<unhandled type: %v>", reflect.TypeOf(v.Value)) 171 } 172 return nil 173 } 174 175 func (v *GeneralValue) String() string { 176 k := reflect.TypeOf(v.Value).Kind() 177 if k != reflect.Ptr { 178 return fmt.Sprintf("<unhandled type: %v>", k) 179 } 180 e := reflect.ValueOf(v.Value).Elem() 181 switch e.Kind() { 182 case reflect.Slice: 183 var buffer strings.Builder 184 count := e.Len() 185 for i := 0; i < count; i++ { 186 if buffer.Len() != 0 { 187 buffer.WriteString(", ") 188 } 189 fmt.Fprintf(&buffer, "%v", e.Index(i)) 190 } 191 return buffer.String() 192 case reflect.String: 193 return fmt.Sprintf(`"%s"`, e) //nolint:gocritic // We don't want escape sequences, so can't use %q 194 default: 195 return fmt.Sprintf("%v", e) 196 } 197 }