(dst []*string)
| 199 | } |
| 200 | |
| 201 | func (csvr *csvReader) csvReadRecords(dst []*string) ([]*string, error) { |
| 202 | recordStartline := csvr.numLine // Starting line for record |
| 203 | |
| 204 | var rs recordState |
| 205 | var err error |
| 206 | for err == nil { |
| 207 | rs = recordState{} |
| 208 | rs.line, err = csvr.readLine() |
| 209 | rs.rawData = append(rs.rawData, rs.line...) |
| 210 | |
| 211 | if err == nil && len(rs.line) == lengthNL(rs.line) { |
| 212 | continue // Skip empty lines |
| 213 | } |
| 214 | break |
| 215 | } |
| 216 | if err != nil { |
| 217 | return nil, err |
| 218 | } |
| 219 | |
| 220 | // nullString indicates whether to interpret an empty string as a NULL |
| 221 | // only empty strings escaped with double quotes will be non-null |
| 222 | nullString := make(map[int]bool) |
| 223 | fieldIdx := 0 |
| 224 | |
| 225 | kontinue := true |
| 226 | for kontinue { |
| 227 | // Parse each field in the record. |
| 228 | keep := true |
| 229 | if len(rs.line) == 0 || rs.line[0] != '"' { |
| 230 | kontinue, keep, err = csvr.parseField(&rs) |
| 231 | if !keep { |
| 232 | nullString[fieldIdx] = true |
| 233 | } |
| 234 | } else { |
| 235 | kontinue, err = csvr.parseQuotedField(&rs) |
| 236 | if err != nil { |
| 237 | return nil, err |
| 238 | } |
| 239 | } |
| 240 | fieldIdx++ |
| 241 | } |
| 242 | |
| 243 | // Create a single string and create slices out of it. |
| 244 | // This pins the memory of the fields together, but allocates once. |
| 245 | str := string(rs.recordBuffer) // Convert to string once to batch allocations |
| 246 | dst = dst[:0] |
| 247 | if cap(dst) < len(rs.fieldIndexes) { |
| 248 | dst = make([]*string, len(rs.fieldIndexes)) |
| 249 | } |
| 250 | dst = dst[:len(rs.fieldIndexes)] |
| 251 | var preIdx int |
| 252 | for i, idx := range rs.fieldIndexes { |
| 253 | _, ok := nullString[i] |
| 254 | if ok { |
| 255 | dst[i] = nil |
| 256 | } else { |
| 257 | s := str[preIdx:idx] |
| 258 | dst[i] = &s |
no test coverage detected