Tool refactoring
This commit is contained in:
120
archive/tools/util/csv.cpp
Normal file
120
archive/tools/util/csv.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
/**
|
||||
* 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);
|
||||
}
|
Reference in New Issue
Block a user