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);
 | |
| } |