You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

convert.go 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. // Copyright 2012 Jesse van den Kieboom. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package flags
  5. import (
  6. "fmt"
  7. "reflect"
  8. "strconv"
  9. "strings"
  10. "time"
  11. )
  12. // Marshaler is the interface implemented by types that can marshal themselves
  13. // to a string representation of the flag.
  14. type Marshaler interface {
  15. // MarshalFlag marshals a flag value to its string representation.
  16. MarshalFlag() (string, error)
  17. }
  18. // Unmarshaler is the interface implemented by types that can unmarshal a flag
  19. // argument to themselves. The provided value is directly passed from the
  20. // command line.
  21. type Unmarshaler interface {
  22. // UnmarshalFlag unmarshals a string value representation to the flag
  23. // value (which therefore needs to be a pointer receiver).
  24. UnmarshalFlag(value string) error
  25. }
  26. func getBase(options multiTag, base int) (int, error) {
  27. sbase := options.Get("base")
  28. var err error
  29. var ivbase int64
  30. if sbase != "" {
  31. ivbase, err = strconv.ParseInt(sbase, 10, 32)
  32. base = int(ivbase)
  33. }
  34. return base, err
  35. }
  36. func convertMarshal(val reflect.Value) (bool, string, error) {
  37. // Check first for the Marshaler interface
  38. if val.Type().NumMethod() > 0 && val.CanInterface() {
  39. if marshaler, ok := val.Interface().(Marshaler); ok {
  40. ret, err := marshaler.MarshalFlag()
  41. return true, ret, err
  42. }
  43. }
  44. return false, "", nil
  45. }
  46. func convertToString(val reflect.Value, options multiTag) (string, error) {
  47. if ok, ret, err := convertMarshal(val); ok {
  48. return ret, err
  49. }
  50. tp := val.Type()
  51. // Support for time.Duration
  52. if tp == reflect.TypeOf((*time.Duration)(nil)).Elem() {
  53. stringer := val.Interface().(fmt.Stringer)
  54. return stringer.String(), nil
  55. }
  56. switch tp.Kind() {
  57. case reflect.String:
  58. return val.String(), nil
  59. case reflect.Bool:
  60. if val.Bool() {
  61. return "true", nil
  62. }
  63. return "false", nil
  64. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  65. base, err := getBase(options, 10)
  66. if err != nil {
  67. return "", err
  68. }
  69. return strconv.FormatInt(val.Int(), base), nil
  70. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  71. base, err := getBase(options, 10)
  72. if err != nil {
  73. return "", err
  74. }
  75. return strconv.FormatUint(val.Uint(), base), nil
  76. case reflect.Float32, reflect.Float64:
  77. return strconv.FormatFloat(val.Float(), 'g', -1, tp.Bits()), nil
  78. case reflect.Slice:
  79. if val.Len() == 0 {
  80. return "", nil
  81. }
  82. ret := "["
  83. for i := 0; i < val.Len(); i++ {
  84. if i != 0 {
  85. ret += ", "
  86. }
  87. item, err := convertToString(val.Index(i), options)
  88. if err != nil {
  89. return "", err
  90. }
  91. ret += item
  92. }
  93. return ret + "]", nil
  94. case reflect.Map:
  95. ret := "{"
  96. for i, key := range val.MapKeys() {
  97. if i != 0 {
  98. ret += ", "
  99. }
  100. keyitem, err := convertToString(key, options)
  101. if err != nil {
  102. return "", err
  103. }
  104. item, err := convertToString(val.MapIndex(key), options)
  105. if err != nil {
  106. return "", err
  107. }
  108. ret += keyitem + ":" + item
  109. }
  110. return ret + "}", nil
  111. case reflect.Ptr:
  112. return convertToString(reflect.Indirect(val), options)
  113. case reflect.Interface:
  114. if !val.IsNil() {
  115. return convertToString(val.Elem(), options)
  116. }
  117. }
  118. return "", nil
  119. }
  120. func convertUnmarshal(val string, retval reflect.Value) (bool, error) {
  121. if retval.Type().NumMethod() > 0 && retval.CanInterface() {
  122. if unmarshaler, ok := retval.Interface().(Unmarshaler); ok {
  123. if retval.IsNil() {
  124. retval.Set(reflect.New(retval.Type().Elem()))
  125. // Re-assign from the new value
  126. unmarshaler = retval.Interface().(Unmarshaler)
  127. }
  128. return true, unmarshaler.UnmarshalFlag(val)
  129. }
  130. }
  131. if retval.Type().Kind() != reflect.Ptr && retval.CanAddr() {
  132. return convertUnmarshal(val, retval.Addr())
  133. }
  134. if retval.Type().Kind() == reflect.Interface && !retval.IsNil() {
  135. return convertUnmarshal(val, retval.Elem())
  136. }
  137. return false, nil
  138. }
  139. func convert(val string, retval reflect.Value, options multiTag) error {
  140. if ok, err := convertUnmarshal(val, retval); ok {
  141. return err
  142. }
  143. tp := retval.Type()
  144. // Support for time.Duration
  145. if tp == reflect.TypeOf((*time.Duration)(nil)).Elem() {
  146. parsed, err := time.ParseDuration(val)
  147. if err != nil {
  148. return err
  149. }
  150. retval.SetInt(int64(parsed))
  151. return nil
  152. }
  153. switch tp.Kind() {
  154. case reflect.String:
  155. retval.SetString(val)
  156. case reflect.Bool:
  157. if val == "" {
  158. retval.SetBool(true)
  159. } else {
  160. b, err := strconv.ParseBool(val)
  161. if err != nil {
  162. return err
  163. }
  164. retval.SetBool(b)
  165. }
  166. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  167. base, err := getBase(options, 10)
  168. if err != nil {
  169. return err
  170. }
  171. parsed, err := strconv.ParseInt(val, base, tp.Bits())
  172. if err != nil {
  173. return err
  174. }
  175. retval.SetInt(parsed)
  176. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  177. base, err := getBase(options, 10)
  178. if err != nil {
  179. return err
  180. }
  181. parsed, err := strconv.ParseUint(val, base, tp.Bits())
  182. if err != nil {
  183. return err
  184. }
  185. retval.SetUint(parsed)
  186. case reflect.Float32, reflect.Float64:
  187. parsed, err := strconv.ParseFloat(val, tp.Bits())
  188. if err != nil {
  189. return err
  190. }
  191. retval.SetFloat(parsed)
  192. case reflect.Slice:
  193. elemtp := tp.Elem()
  194. elemvalptr := reflect.New(elemtp)
  195. elemval := reflect.Indirect(elemvalptr)
  196. if err := convert(val, elemval, options); err != nil {
  197. return err
  198. }
  199. retval.Set(reflect.Append(retval, elemval))
  200. case reflect.Map:
  201. parts := strings.SplitN(val, ":", 2)
  202. key := parts[0]
  203. var value string
  204. if len(parts) == 2 {
  205. value = parts[1]
  206. }
  207. keytp := tp.Key()
  208. keyval := reflect.New(keytp)
  209. if err := convert(key, keyval, options); err != nil {
  210. return err
  211. }
  212. valuetp := tp.Elem()
  213. valueval := reflect.New(valuetp)
  214. if err := convert(value, valueval, options); err != nil {
  215. return err
  216. }
  217. if retval.IsNil() {
  218. retval.Set(reflect.MakeMap(tp))
  219. }
  220. retval.SetMapIndex(reflect.Indirect(keyval), reflect.Indirect(valueval))
  221. case reflect.Ptr:
  222. if retval.IsNil() {
  223. retval.Set(reflect.New(retval.Type().Elem()))
  224. }
  225. return convert(val, reflect.Indirect(retval), options)
  226. case reflect.Interface:
  227. if !retval.IsNil() {
  228. return convert(val, retval.Elem(), options)
  229. }
  230. }
  231. return nil
  232. }
  233. func isPrint(s string) bool {
  234. for _, c := range s {
  235. if !strconv.IsPrint(c) {
  236. return false
  237. }
  238. }
  239. return true
  240. }
  241. func quoteIfNeeded(s string) string {
  242. if !isPrint(s) {
  243. return strconv.Quote(s)
  244. }
  245. return s
  246. }
  247. func quoteIfNeededV(s []string) []string {
  248. ret := make([]string, len(s))
  249. for i, v := range s {
  250. ret[i] = quoteIfNeeded(v)
  251. }
  252. return ret
  253. }
  254. func quoteV(s []string) []string {
  255. ret := make([]string, len(s))
  256. for i, v := range s {
  257. ret[i] = strconv.Quote(v)
  258. }
  259. return ret
  260. }
  261. func unquoteIfPossible(s string) (string, error) {
  262. if len(s) == 0 || s[0] != '"' {
  263. return s, nil
  264. }
  265. return strconv.Unquote(s)
  266. }