Polishing the CSV and Language Parser(s).

This commit is contained in:
2021-08-09 08:34:49 -07:00
parent 1f3f23a76e
commit 68986fd108
12 changed files with 382 additions and 149 deletions

View File

@ -64,10 +64,15 @@ int32_t assetBufferEnd(assetbuffer_t *buffer) {
return feof((FILE *)buffer);
}
void assetBufferSkip(assetbuffer_t *buffer, int32_t n) {
fseek((FILE *)buffer, n, SEEK_CUR);
int32_t assetBufferStart(assetbuffer_t *buffer) {
return fseek((FILE *)buffer, 0, SEEK_SET);
}
int32_t assetBufferSkip(assetbuffer_t *buffer, int32_t n) {
return fseek((FILE *)buffer, n, SEEK_CUR);
}
void assetShaderLoad(shader_t *shader, char *fileVertex, char *fileFragment) {
// Load the vertex shader into memory
char *vertexShader = assetStringLoad(fileVertex);

View File

@ -48,12 +48,21 @@ int32_t assetBufferRead(assetbuffer_t *buffer, char *data, int32_t size);
*/
int32_t assetBufferEnd(assetbuffer_t *buffer);
/**
* Rewinds an asset buffer to the start.
*
* @param buffer Buffer to rewind
* @return 0 if successful, otherwise unsuccessful.
*/
int32_t assetBufferStart(assetbuffer_t *buffer);
/**
* Method to skip n bytes in the buffer
* @param buffer The buffer pointing to an asset.
* @param n Count of bytes to skip.
* @return 0 if successful, otherwise unsuccessful.
*/
void assetBufferSkip(assetbuffer_t *buffer, int32_t n);
int32_t assetBufferSkip(assetbuffer_t *buffer, int32_t n);
/**
* Load a shader program from a vertex and fragment shader file.

View File

@ -7,15 +7,14 @@
#include "csv.h"
// void csvPopulate(assetbuffer_t *asset, csv_t *output) {
// }
csvbufferresult_t csvBuffer(assetbuffer_t *asset, csvbuffercallback_t *callback, void *user){
csvbufferresult_t csvBuffer(
assetbuffer_t *asset, csvbuffercallback_t *callback, void *user
) {
int32_t cellChar, read, i, currentColumnCount;
char temp[CSV_BUFFER_SIZE];
char cell[CSV_BUFFER_SIZE];
char buffer[CSV_BUFFER_SIZE];
char cell[CSV_CELL_SIZE_MAX];
char c;
bool callbackResponse;
bool insideEncapsulation = false;
csvbufferresult_t result = {
.cellCount = 0,
@ -29,19 +28,19 @@ csvbufferresult_t csvBuffer(assetbuffer_t *asset, csvbuffercallback_t *callback,
// Begin buffering.
while(true) {
// Read n bytes
read = assetBufferRead(asset, temp, CSV_BUFFER_SIZE);
// Read n bytes into our buffer
read = assetBufferRead(asset, buffer, CSV_BUFFER_SIZE);
// Now read back those bytes.
for(i = 0; i < read; i++) {
c = temp[i];
c = buffer[i];
// Characters we flat out ignore
if(c == '\r') continue;
// Handle quote marks.
if(c == '"') {
if(temp[i+1] == '"') {// "" means a single quote (double-escaped)
if(buffer[i+1] == '"') {// "" means a single quote (double-escaped)
i++;
cell[cellChar++] = c;
} else if(insideEncapsulation) {
@ -59,7 +58,8 @@ csvbufferresult_t csvBuffer(assetbuffer_t *asset, csvbuffercallback_t *callback,
// Fire off the callback
if(callback != NULL) {
callback(asset, user, result.rowCount, result.cellCount, cell);
callbackResponse = callback(asset, user, result.rowCount, currentColumnCount, cell);
if(!callbackResponse) return result;
}
// Prepare for next row/cell
@ -84,57 +84,140 @@ csvbufferresult_t csvBuffer(assetbuffer_t *asset, csvbuffercallback_t *callback,
// If this is an empty row we don't count it, otherwise we do.
if(currentColumnCount != 0) result.rowCount++;
// Finish buffering.
assetBufferClose(asset);
return result;
}
void _csvBufferRowParserCallback(assetbuffer_t *asset, void *user, int32_t row, int32_t column, char *data) {
bool _csvBufferRowParserCallback(
assetbuffer_t *asset, void *user, int32_t row, int32_t column, char *data
) {
csvbufferrowdata_t *rowData = (csvbufferrowdata_t *)user;
// Now did we change rows?
if(row != rowData->row) {
// Yes we did, let's buffer the previous row.
rowData->row = row;// Update row, basically this forces 1 indexing.
if(rowData->callback != NULL) {
rowData->callback(
asset, rowData->user, rowData->row,
rowData->columns, rowData->columnCount
);
if(!rowData->callback(
asset, rowData->user, rowData->row, &rowData->rowCurrent
)) return false;
}
rowData->columnCount = 0;
// Begin next row
rowData->row = row;
rowData->rowCurrent.columnCount = 0;
}
// Determine string info for the cell
int32_t length = strlen(data);
int32_t offset = (column * CSV_BUFFER_ROW_SIZE);
int32_t offset = (column * CSV_CELL_SIZE_MAX);
// Now copy that data to the buffer
arrayCopy(
sizeof(char), data, length + 1,
rowData->rowData + offset
);
rowData->columns[column] = rowData->rowData + offset;
rowData->columnCount++;
// Now copy the string data to the buffer
arrayCopy(sizeof(char), data, length + 1, rowData->rowCurrent.data + offset);
// Update the pointer to the string
rowData->rowCurrent.columns[column] = rowData->rowCurrent.data + offset;
rowData->rowCurrent.columnCount++;
return true;
}
csvbufferresult_t csvBufferRow(assetbuffer_t *asset, csvbufferrowcallback_t *callback, void *user) {
csvbufferresult_t csvBufferRow(
assetbuffer_t *asset, csvbufferrowcallback_t *callback, void *user
) {
csvbufferrowdata_t data;
csvbufferresult_t result;
data.row = 0;
data.columnCount = 0;
data.user = user;
data.callback = callback;
data.rowCurrent.columnCount = 0;
// Perform a per-cell buffer and run the parser callback.
result = csvBuffer(asset, &_csvBufferRowParserCallback, &data);
// Because the buffer may not fire for the last row we handle it here.
if(data.columnCount > 0 && callback != NULL) {
data.row++;// Because .row is 0 indexed until the "next line", we increment
callback(asset, user, data.row, data.columns, data.columnCount);
if(data.rowCurrent.columnCount > 0 && callback != NULL) {
if(!callback(asset, user, data.row, &data.rowCurrent)) return result;
}
return result;
}
bool _csvBufferRowWithHeadersCallback(
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *csv
) {
csvbufferrowwithheadersdata_t *data = (csvbufferrowwithheadersdata_t *)user;
int32_t i;
// Take the headers for row 0
if(row == 0) {
csvRowPopulate(csv, &data->headerRow);
return true;
}
// Fire the callback
return data->callback(asset, data->user, row, &data->headerRow, csv);
}
csvbufferresult_t csvBufferRowWithHeaders(
assetbuffer_t *asset, csvbufferrowwitheaderscallback_t *callback, void *user
) {
csvbufferrowwithheadersdata_t data;
data.user = user;
data.callback = callback;
return csvBufferRow(asset, &_csvBufferRowWithHeadersCallback, &data);
}
void csvRowPopulate(csvrow_t *source, csvrow_t *dest) {
int32_t i;
dest->columnCount = source->columnCount;
// Copy the raw characters from the source buffer.
arrayCopy(sizeof(char), source->data, CSV_ROW_CHARACTERS_MAX, dest->data);
// Now update the destination pointers to reference the data buffer.
for(i = 0; i < source->columnCount; i++) {
dest->columns[i] = dest->data + (i * CSV_CELL_SIZE_MAX);
}
}
bool _csvHeadersGetCallback(
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *current
) {
csvrow_t *rowData = (csvrow_t *)user;
csvRowPopulate(current, rowData);
return false;// False to break the loop
}
csvbufferresult_t csvHeadersGet(assetbuffer_t *asset, csvrow_t *row) {
return csvBufferRow(asset, &_csvHeadersGetCallback, row);
}
int32_t csvColumnGetIndex(csvrow_t *row, char *key) {
return arrayFindString(row->columns, row->columnCount, key);
}
bool _csvRowSearchCallback(
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *csv
) {
csvsearchdata_t *data = (csvsearchdata_t *)user;
// Does the search match?
if(strcmp(csv->columns[data->column], data->value) != 0) return true;
// Matched, copy and end.
csvRowPopulate(csv, data->row);
data->rowIndex = row;
return false;
}
int32_t csvRowSearch(
assetbuffer_t *asset, csvrow_t *row, int32_t column, char *value
) {
csvsearchdata_t data = {
.column = column,
.row = row,
.rowIndex = -1,
.value = value
};
csvBufferRow(asset, &_csvRowSearchCallback, &data);
return data.rowIndex;
}

View File

@ -10,7 +10,101 @@
#include "asset.h"
#include "../util/array.h"
csvbufferresult_t csvBuffer(assetbuffer_t *asset, csvbuffercallback_t *callback, void *user);
/**
* Buffer each cell within a CSV Asset Buffer with a callback.
*
* @param asset Asset to buffer the CSV from.
* @param callback Callback to fire for each cell parsed.
* @param user Pointer to any custom user data.
* @return The result of the CSV Buffer Operation.
*/
csvbufferresult_t csvBuffer(
assetbuffer_t *asset, csvbuffercallback_t *callback, void *user
);
void _csvBufferRowParserCallback(assetbuffer_t *asset, void *user, int32_t row, int32_t column, char *data);
csvbufferresult_t csvBufferRow(assetbuffer_t *asset, csvbufferrowcallback_t *callback, void *user);
/** Callback for when the CSV Row Buffer is parsing a row */
bool _csvBufferRowParserCallback(
assetbuffer_t *asset, void *user, int32_t row, int32_t column, char *data
);
/**
* Buffer each row within a CSV Asset Buffer with a callback.
*
* @param asset Asset to buffer the CSV from.
* @param callback Callback to fire when a row is parsed.
* @param user Pointer to any custom user data.
* @return The result of the CSV Buffer Operation.
*/
csvbufferresult_t csvBufferRow(
assetbuffer_t *asset, csvbufferrowcallback_t *callback, void *user
);
/** Parser that the header parser buffer uses. */
bool _csvBufferRowWithHeadersCallback(
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *csv
);
/**
* Buffer each row within a CSV Asset Buffer with a callback. This will also
* provide the callback with the header row (The first row), already parsed.
*
* @param asset
* @param callback
* @param user
* @return csvbufferresult_t
*/
csvbufferresult_t csvBufferRowWithHeaders(
assetbuffer_t *asset, csvbufferrowwitheaderscallback_t *callback, void *user
);
/**
* Essentially a CSV Row Cloner, copies data from one CSV row to another and
* updates the char pointers for you.
*
* @param source The source CSV row to copy from.
* @param dest The destination CSV row to copy to.
*/
void csvRowPopulate(csvrow_t *source, csvrow_t *dest);
/** Callback used to parse and get the headers row */
bool _csvHeadersGetCallback(
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *current
);
/**
* Parses just the headers row from a CSV and stores the output into the
* provided buffers.
*
* @param asset Asset to get the headers from.
* @param row The CSV Row to store the headers data in.
* @return The result of the buffer operation.
*/
csvbufferresult_t csvHeadersGet(assetbuffer_t *asset, csvrow_t *row);
/**
* Gets the column index within the CSV Row for the specific key.
* @param row Row to get from.
* @param key Key to search for
* @return The column index for the key, or -1 if not found.
*/
int32_t csvColumnGetIndex(csvrow_t *row, char *key);
/** Callback to use while scanning the CSV to find the matching row */
bool _csvRowSearchCallback(
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *csv
);
/**
* Search the CSV for a matching row. Will return data only if the given column
* matches the given value.
*
* @param asset Asset buffer to search.
* @param row Where the returned row will be stored.
* @param column Column to check.
* @param value Value to check in that column
* @return The row index that the result was found on, or -1 if not found.
*/
int32_t csvRowSearch(
assetbuffer_t *asset, csvrow_t *row, int32_t column, char *value
);