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  }