Built & tested gs_csv.h

This commit is contained in:
PS 2021-03-24 19:09:26 -07:00
parent 4085d3acf9
commit 743181fe9b
3 changed files with 262 additions and 6 deletions

View File

@ -507,7 +507,7 @@ SetWorkingDirectory(HINSTANCE HInstance, gs_thread_context ThreadContext)
{
OutputDebugStringA("Setting Working Directory\n");
OutputDebugStringA(WorkingDirectory.Str);
OutputDebugStringA("\n");
Result = SetCurrentDirectory(WorkingDirectory.Str);
if (!Result)
{
@ -525,6 +525,8 @@ SetWorkingDirectory(HINSTANCE HInstance, gs_thread_context ThreadContext)
#include "../../gs_libs/gs_path.h"
#include "../../gs_libs/gs_csv.h"
int WINAPI
WinMain (
HINSTANCE HInstance,
@ -541,13 +543,29 @@ WinMain (
ThreadContext.Allocator.Debug = &AllocDebug;
gs_file_info A = GetFileInfo(ThreadContext.FileHandler, ConstString("C:\\projects\\Lumenarium"));
gs_file_info B = GetFileInfo(ThreadContext.FileHandler, ConstString("C:\\projects\\Lumenarium\\"));
if (!SetWorkingDirectory(HInstance, ThreadContext)) return 1;
gs_file TestFile = ReadEntireFile(ThreadContext.FileHandler, ConstString("data/flower_codes.tsv"));
gs_const_string TestFileStr = {};
TestFileStr.Str = (char*)TestFile.Memory;
TestFileStr.Length = TestFile.Size;
gscsv_sheet Sheet = CSV_Parse(TestFileStr, { '\t' }, ThreadContext.Transient);
gs_string Out = PushString(ThreadContext.Transient, TestFile.Size * 2);
for (u64 y = 0; y < Sheet.RowCount; y++)
{
for (u64 x = 0; x < Sheet.ColumnCount; x++)
{
gs_const_string Cell = CSVSheet_GetCell(Sheet, x, y);
AppendPrintF(&Out, "%S\t", Cell);
}
AppendPrintF(&Out, "\n");
}
NullTerminate(&Out);
OutputDebugStringA(Out.Str);
MainWindow = Win32CreateWindow (HInstance, "Foldhaus", 1440, 768, HandleWindowEvents);
Win32UpdateWindowDimension(&MainWindow);

214
src/gs_libs/gs_csv.h Normal file
View File

@ -0,0 +1,214 @@
/* date = March 24th 2021 5:53 pm */
#ifndef GS_CSV_H
#define GS_CSV_H
struct gscsv_cell
{
gs_const_string Value;
};
struct gscsv_row
{
u64* CellIndices;
};
struct gscsv_sheet
{
char SeparatorChar;
gscsv_cell* Cells;
gscsv_row* Rows;
u64 RowCount;
u64 ColumnCount;
};
struct gscsv_sheet_desc
{
char SeparatorChar;
};
struct gscsv_parser
{
gs_const_string Str;
u64 At;
u64 Line;
};
internal void
CSVParser_Reset(gscsv_parser* Parser)
{
Parser->At = 0;
}
internal char
CSVParser_CharAt(gscsv_parser Parser)
{
char Result = Parser.Str.Str[Parser.At];
return Result;
}
internal bool
CSVParser_CanAdvance(gscsv_parser Parser) {
bool Result = Parser.At < Parser.Str.Length;
return Result;
}
internal void
CSVParser_Advance(gscsv_parser* Parser)
{
if (CSVParser_CanAdvance(*Parser)) {
if (IsNewline(CSVParser_CharAt(*Parser)))
{
Parser->Line += 1;
}
Parser->At += 1;
}
}
internal void
CSVParser_AdvancePastChar(gscsv_parser* Parser, char Char)
{
while (CSVParser_CanAdvance(*Parser) && CSVParser_CharAt(*Parser) != Char)
{
CSVParser_Advance(Parser);
}
if (CSVParser_CanAdvance(*Parser))
{
Assert(CSVParser_CharAt(*Parser) == Char);
CSVParser_Advance(Parser);
}
}
internal u64
CSVParser_AdvancePastSeparatorOrNewline(gscsv_parser* Parser, char SeparatorChar)
{
u64 PointBeforeSeparator = 0;
while (CSVParser_CanAdvance(*Parser) &&
!(CSVParser_CharAt(*Parser) == SeparatorChar ||
IsNewline(CSVParser_CharAt(*Parser))))
{
CSVParser_Advance(Parser);
}
PointBeforeSeparator = Parser->At;
if (CSVParser_CanAdvance(*Parser))
{
while(IsNewline(CSVParser_CharAt(*Parser))) {
CSVParser_Advance(Parser);
}
if (CSVParser_CharAt(*Parser) == SeparatorChar)
{
CSVParser_Advance(Parser);
}
}
return PointBeforeSeparator;
}
internal gscsv_cell
CSVCell_Init(gs_const_string File, u64 CellStart, u64 CellEnd)
{
gscsv_cell Result = {};
Result.Value = Substring(File, CellStart, CellEnd);
return Result;
}
internal void
CSVRow_PushCell(gscsv_row* Row, u64 CellIndex, u64 ColumnIndex)
{
Row->CellIndices[ColumnIndex] = CellIndex;
}
internal gscsv_sheet
CSV_Parse(gs_const_string File, gscsv_sheet_desc Desc, gs_memory_arena* Arena)
{
gscsv_sheet Result = {};
gscsv_parser Parser = {};
Parser.Str = File;
Parser.At = 0;
Parser.Line = 0;
// Count Tabs in first line
u64 Columns = 0;
while (CSVParser_CanAdvance(Parser) && !IsNewline(CSVParser_CharAt(Parser)))
{
char At = CSVParser_CharAt(Parser);
if (At == Desc.SeparatorChar) {
Columns += 1;
}
CSVParser_Advance(&Parser);
}
// NOTE(PS): Add one on the end because the last column won't end in a SeparatorChar,
// it ends in a newline
Columns += 1;
CSVParser_Reset(&Parser);
// Count New Lines
u64 Rows = 0;
while (CSVParser_CanAdvance(Parser))
{
char At = CSVParser_CharAt(Parser);
if (IsNewline(At))
{
Rows++;
while (CSVParser_CanAdvance(Parser) && IsNewline(CSVParser_CharAt(Parser)))
{
CSVParser_Advance(&Parser);
}
} else {
CSVParser_Advance(&Parser);
}
}
// NOTE(PS): Adding a row becuase the last row will just end in the EOF
Rows += 1;
CSVParser_Reset(&Parser);
// Allocate Result
Result.SeparatorChar = Desc.SeparatorChar;
Result.RowCount = Rows;
Result.ColumnCount = Columns;
Result.Cells = PushArray(Arena, gscsv_cell, Result.RowCount * Result.ColumnCount);
Result.Rows = PushArray(Arena, gscsv_row, Result.RowCount);
// for rows, parse row
// for cells parse cells
for (u64 r = 0; r < Result.RowCount; r++)
{
u64 RowIndex = r;
gscsv_row* Row = Result.Rows + RowIndex;
Row->CellIndices = PushArray(Arena, u64, Result.ColumnCount);
for (u64 c = 0; c < Result.ColumnCount; c++)
{
u64 CellIndex = (r * Result.ColumnCount) + c;
u64 CellStart = Parser.At;
u64 CellEnd = CSVParser_AdvancePastSeparatorOrNewline(&Parser, Desc.SeparatorChar);
Result.Cells[CellIndex] = CSVCell_Init(Parser.Str, CellStart, CellEnd);
CSVRow_PushCell(Row, CellIndex, c);
}
}
return Result;
}
internal gs_const_string
CSVSheet_GetCell(gscsv_sheet Sheet, u64 Column, u64 Row)
{
gs_const_string Result = {};
if (Sheet.RowCount > Row && Sheet.ColumnCount > Column)
{
u64 CellIndex = (Row * Sheet.ColumnCount) + Column;
Result = Sheet.Cells[CellIndex].Value;
}
return Result;
}
#endif //GS_CSV_H

View File

@ -11,6 +11,7 @@
#include "../gs_libs/gs_tests.h"
#include "../gs_libs/gs_path.h"
#include "../gs_libs/gs_csv.h"
gs_memory_arena Scratch = {};
void* Alloc(u64 Size, u64* ResultSize) { *ResultSize = Size; return malloc(Size); }
@ -29,6 +30,11 @@ bool PathTest (char* In, char* Out) {
return StringsEqual(SanitizePath(ConstString(In), &Scratch), ConstString(Out));
}
global char* SampleCSV = R"FOO(Flower Primary Hue (0-365) Secondary Hue (0-365) Tertiary Hue (0-365) Homonyms
Flower A 55 32 128 foo, bar, blah, baz, whatever
Flower B 123 344 32 foo, bar, blah, baz, whatever
Flower C 55 32 128 foo, bar, blah, baz, whatever)FOO";
int main (int ArgCount, char** Args)
{
Scratch = CreateMemoryArena(CreateAllocator(Alloc, Free), "Scratch");
@ -99,6 +105,24 @@ int main (int ArgCount, char** Args)
TestResult(PathTest("C:\\hello\\world\\.\\test", "C:\\hello\\world\\test"));
}
Test("gs_csv.h")
{
gs_const_string TestCSV = ConstString(SampleCSV);
gscsv_sheet Sheet = CSV_Parse(TestCSV, { '\t' }, &Scratch);
gs_const_string Cell = CSVSheet_GetCell(Sheet, 0, 0);
TestResult(StringsEqual(Cell, ConstString("Flower")));
Cell = CSVSheet_GetCell(Sheet, 1, 1);
TestResult(StringsEqual(Cell, ConstString("55")));
Cell = CSVSheet_GetCell(Sheet, 4, 1);
TestResult(StringsEqual(Cell, ConstString("foo, bar, blah, baz, whatever")));
Cell = CSVSheet_GetCell(Sheet, 4, 3);
TestResult(StringsEqual(Cell, ConstString("foo, bar, blah, baz, whatever")));
}
return 0;
}