ParseCopyOptions parses the options string and returns the CopyOptions. The options string is a comma-separated list of key-value pairs: `OPT1 1, OPT2, OPT3 'v3', OPT4 E'v4', ...`. The allowed map specifies the allowed options and their types. Its keys are the option names in uppercase.
(options string, allowed map[string]OptionValueType)
| 88 | // The options string is a comma-separated list of key-value pairs: `OPT1 1, OPT2, OPT3 'v3', OPT4 E'v4', ...`. |
| 89 | // The allowed map specifies the allowed options and their types. Its keys are the option names in uppercase. |
| 90 | func ParseCopyOptions(options string, allowed map[string]OptionValueType) (result map[string]any, err error) { |
| 91 | result = make(map[string]any) |
| 92 | var key, value string |
| 93 | inQuotes := false |
| 94 | expectComma := false |
| 95 | readingKey := true |
| 96 | var sb strings.Builder |
| 97 | |
| 98 | parseOption := func() error { |
| 99 | k := strings.TrimSpace(key) |
| 100 | if k == "" { |
| 101 | return nil |
| 102 | } |
| 103 | k = strings.ToUpper(k) |
| 104 | if _, ok := allowed[k]; !ok { |
| 105 | return fmt.Errorf("unsupported option: %s", k) |
| 106 | } |
| 107 | v := strings.TrimSpace(value) |
| 108 | |
| 109 | switch allowed[k] { |
| 110 | case OptionValueTypeBool: |
| 111 | if v == "" { |
| 112 | result[k] = true |
| 113 | } else { |
| 114 | val, err := strconv.ParseBool(v) |
| 115 | if err != nil { |
| 116 | return fmt.Errorf("invalid bool value for %s: %v", k, err) |
| 117 | } |
| 118 | result[k] = val |
| 119 | } |
| 120 | case OptionValueTypeInt: |
| 121 | val, err := strconv.Atoi(v) |
| 122 | if err != nil { |
| 123 | return fmt.Errorf("invalid int value for %s: %v", k, err) |
| 124 | } |
| 125 | result[k] = val |
| 126 | case OptionValueTypeFloat: |
| 127 | val, err := strconv.ParseFloat(v, 64) |
| 128 | if err != nil { |
| 129 | return fmt.Errorf("invalid float value for %s: %v", k, err) |
| 130 | } |
| 131 | result[k] = val |
| 132 | case OptionValueTypeString: |
| 133 | if strings.HasPrefix(v, `E'`) && strings.HasSuffix(v, `'`) { |
| 134 | // Remove the 'E' prefix and unescape the value |
| 135 | unquoted, err := strconv.Unquote(`"` + v[2:len(v)-1] + `"`) |
| 136 | if err != nil { |
| 137 | return fmt.Errorf("invalid escaped string value for %s: %v", k, err) |
| 138 | } |
| 139 | v = unquoted |
| 140 | } else if strings.HasPrefix(v, "'") && strings.HasSuffix(v, "'") { |
| 141 | // Trim the single quotes |
| 142 | v = v[1 : len(v)-1] |
| 143 | // Replace double single quotes with a single quote |
| 144 | v = strings.ReplaceAll(v, "''", "'") |
| 145 | } else { |
| 146 | return fmt.Errorf("invalid string value for %s: %q", k, v) |
| 147 | } |