* Parse a CSV file. */
| 224 | * Parse a CSV file. |
| 225 | */ |
| 226 | static void parseCSV(const char *filename, Data &data) |
| 227 | { |
| 228 | FILE *stream = fopen(filename, "r"); |
| 229 | if (stream == nullptr) |
| 230 | error("failed to open CSV file \"%s\" for reading: %s", filename, |
| 231 | strerror(errno)); |
| 232 | |
| 233 | CSV csv = {stream, filename, -1, 0}; |
| 234 | while (true) |
| 235 | { |
| 236 | Record record; |
| 237 | if (!parseRecord(csv, record)) |
| 238 | break; |
| 239 | if (csv.length < 0) |
| 240 | csv.length = (unsigned)record.size(); |
| 241 | else if ((unsigned)record.size() != (unsigned)csv.length) |
| 242 | error("failed to parse CSV file \"%s\" at line %u; record with " |
| 243 | "invalid length %zu (expected %u)", csv.filename, |
| 244 | csv.lineno, record.size(), csv.length); |
| 245 | MatchVal &addr = record[0]; |
| 246 | if (addr.type != MATCH_TYPE_INTEGER) |
| 247 | error("failed to parse CSV file \"%s\" at line %u; first record " |
| 248 | "entry must be an address", csv.filename, csv.lineno); |
| 249 | auto r = data.emplace(std::piecewise_construct, |
| 250 | std::make_tuple(addr.i), std::make_tuple()); |
| 251 | if (!r.second) |
| 252 | error("failed to parse CSV file \"%s\" at line %u; duplicate " |
| 253 | "record with address 0x%lx", csv.filename, csv.lineno, |
| 254 | addr); |
| 255 | record.shrink_to_fit(); |
| 256 | record.swap(r.first->second); |
| 257 | } |
| 258 | |
| 259 | fclose(stream); |
| 260 | } |
| 261 | |
| 262 | /* |
| 263 | * Lookup a value from a CSV file. |
no test coverage detected