Polishing the CSV and Language Parser(s).
This commit is contained in:
@ -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);
|
||||
|
@ -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.
|
||||
|
153
src/file/csv.c
153
src/file/csv.c
@ -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;
|
||||
}
|
100
src/file/csv.h
100
src/file/csv.h
@ -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
|
||||
);
|
Reference in New Issue
Block a user