120 lines
3.5 KiB
C++
120 lines
3.5 KiB
C++
/**
|
|
* Copyright (c) 2022 Dominic Masters
|
|
*
|
|
* This software is released under the MIT License.
|
|
* https://opensource.org/licenses/MIT
|
|
*/
|
|
|
|
#include "csv.hpp"
|
|
|
|
char * csvGetCell(csv_t *csv, int32_t row, int32_t cell) {
|
|
return csv->rows[(row * CSV_COLUMN_COUNT_MAX) + cell];
|
|
}
|
|
|
|
void csvParse(char *string, csv_t *csv) {
|
|
char c;
|
|
size_t i, j, length;
|
|
csvparsestate_t state;
|
|
int32_t rowCellCount;
|
|
|
|
length = strlen(string);
|
|
csv->buffer = (char *)malloc(sizeof(char) * (length+1) * CSV_COLUMN_COUNT_MAX * CSV_ROW_COUNT_MAX);
|
|
csv->cellCounts = (int32_t *)malloc(sizeof(int32_t) * CSV_ROW_COUNT_MAX);
|
|
csv->rows = (char**)malloc(sizeof(char*) * CSV_ROW_COUNT_MAX * CSV_COLUMN_COUNT_MAX);
|
|
|
|
i = 0;
|
|
j = 0;
|
|
rowCellCount = 0;
|
|
csv->rowCount = 0;
|
|
state = CSV_PARSE_STATE_FIND_CELL;
|
|
while(i < length) {
|
|
c = string[i++];
|
|
|
|
// What are we doing
|
|
switch(state) {
|
|
case CSV_PARSE_STATE_FIND_CELL:
|
|
if(c == '"') {
|
|
state = CSV_PARSE_STATE_PARSE_CELL_WITH_QUOTES;
|
|
csv->rows[(csv->rowCount * CSV_COLUMN_COUNT_MAX) + rowCellCount] = csv->buffer + j;
|
|
rowCellCount++;
|
|
continue;
|
|
} else if(c == '\r' || c == '\n') {
|
|
// Newline (todo: is this a blank line?)
|
|
state = CSV_PARSE_STATE_LINE_END;
|
|
continue;
|
|
} else if(c == ',') {
|
|
csv->rows[(csv->rowCount * CSV_COLUMN_COUNT_MAX) + rowCellCount] = csv->buffer + j;
|
|
csv->buffer[j++] = '\0';
|
|
rowCellCount++;
|
|
continue;
|
|
} else {
|
|
state = CSV_PARSE_STATE_PARSE_CELL;
|
|
csv->rows[(csv->rowCount * CSV_COLUMN_COUNT_MAX) + rowCellCount] = csv->buffer + j;
|
|
csv->buffer[j++] = c;
|
|
rowCellCount++;
|
|
continue;
|
|
}
|
|
|
|
case CSV_PARSE_STATE_PARSE_CELL:
|
|
if(c == '\r' || c == '\n') {
|
|
state = CSV_PARSE_STATE_LINE_END;
|
|
csv->buffer[j++] = '\0';
|
|
continue;
|
|
} else if(c == ',') {
|
|
state = CSV_PARSE_STATE_FIND_CELL;
|
|
csv->buffer[j++] = '\0';
|
|
continue;
|
|
}
|
|
csv->buffer[j++] = c;
|
|
continue;
|
|
|
|
case CSV_PARSE_STATE_PARSE_CELL_WITH_QUOTES:
|
|
if((c == '\\' && string[i] == '"') || (c == '"' && string[i] == '"')) {
|
|
// Handle escaped quotes. I normally see [\"] but excel does [""] in
|
|
// most cases
|
|
csv->buffer[j++] = '"';
|
|
i++;
|
|
continue;
|
|
} else if(c == '"') {
|
|
// Handle end of quoted string
|
|
state = CSV_PARSE_STATE_FIND_CELL;
|
|
csv->buffer[j++] = '\0';
|
|
// Because we tend to do [",] at the end of a quoted cell, we do this
|
|
// to prevent [,,] cases being treated the same
|
|
if(string[i] == ',') i++;
|
|
continue;
|
|
}
|
|
|
|
// Normal character.
|
|
csv->buffer[j++] = c;
|
|
continue;
|
|
|
|
case CSV_PARSE_STATE_LINE_END:
|
|
// Skip blanks
|
|
if(c == '\r' || c == '\n') continue;
|
|
csv->cellCounts[csv->rowCount] = rowCellCount;
|
|
csv->rowCount++;
|
|
rowCellCount = 0;
|
|
state = CSV_PARSE_STATE_FIND_CELL;
|
|
i--;
|
|
continue;
|
|
|
|
default:
|
|
printf("Error occured during parse operation.");
|
|
free(NULL);
|
|
}
|
|
}
|
|
|
|
csv->buffer[j++] = '\0';
|
|
|
|
if(rowCellCount != 0) {
|
|
csv->cellCounts[csv->rowCount] = rowCellCount;
|
|
csv->rowCount++;
|
|
}
|
|
}
|
|
|
|
void csvDispose(csv_t *csv) {
|
|
free(csv->buffer);
|
|
free(csv->cellCounts);
|
|
free(csv->rows);
|
|
} |