TU-Programmieren_2/lab3/modules/iue-io/ccsv.h
2025-04-09 10:22:44 +02:00

143 lines
4.2 KiB
C

#pragma once
#include <assert.h> // assert
#include <math.h> // NAN
#include <stddef.h> // size_t
#include <stdio.h> // FILE|snprintf
#include <stdlib.h> // EXIT_FAILURE|EXIT_SUCCESS
#include <string.h> // strtok|strdup|memcpy
/// @brief Set of values in a row
struct Row {
double* values; ///< pointer to row value array
size_t n; ///< length of array 'value'
};
/// @brief Set of rows
struct Table {
struct Row* rows; ///< pointer to array of rows
size_t n; ///< length of array 'rows'
};
static void table_clear(struct Table* table) {
for (size_t i = 0; i != table->n; ++i) {
free(table->rows[i].values);
}
free(table->rows);
table->rows = NULL;
table->n = 0;
}
static void table_append_copy(struct Table* table, const double* data, size_t n) {
assert(table != NULL);
table->rows = realloc(table->rows, sizeof(struct Row) * ++table->n);
double* ptr = malloc(sizeof(double) * n);
memcpy(ptr, data, sizeof(double) * n);
table->rows[table->n - 1].values = ptr;
table->rows[table->n - 1].n = n;
}
static void table_append_move(struct Table* table, const struct Row* row) {
assert(table != NULL);
table->rows = realloc(table->rows, sizeof(struct Row) * ++table->n);
table->rows[table->n - 1] = *row;
}
/// @brief Deserialize a row from a string
static void row_serialize(const struct Row* row, FILE* stream, char del) {
for (size_t r = 0; r != row->n - 1; ++r) {
fprintf(stream, "%.18e%c", row->values[r], del);
}
fprintf(stream, "%.18e", row->values[row->n - 1]); // avoid trailing return
fprintf(stream, "\n");
}
/// @brief Writes a numeric values to a file using a csv-format
/// @param filepath file to be written including the desired extension
/// @param table table with the rows to be written
/// @param del delimiter between individual values
/// @param header informative comment in the output file
/// @param comments character signalling that a line is a comment (if used as first character of the line )
static int iueio_savetxt(const char* filepath, const struct Table* table, char del, const char* header, char comments) {
// check if data is present
if (table->n == 0)
return EXIT_SUCCESS;
// open file
FILE* stream = fopen(filepath, "w");
if (stream == NULL)
return EXIT_FAILURE;
// write header lines
if (header[0] != '\0') {
char* tmp = malloc((strlen(header) + 1) * sizeof(char));
strcpy(tmp, header);
char* pos = strtok(tmp, "\n");
while (pos != NULL) {
fprintf(stream, "%c %s%c\n", comments, pos, del);
pos = strtok(NULL, "\n");
}
free(tmp);
}
// write data
for (size_t i = 0; i != table->n; ++i) {
row_serialize(&table->rows[i], stream, del);
}
fclose(stream);
return EXIT_SUCCESS;
}
/// @brief Serializes a Row from a stream
static int row_deserialize(struct Row* row, const char* line, char del) {
assert(row->n == 0);
char format[32];
// snprintf(format, sizeof(format) / sizeof(char), "%%lf %c", del);
double value = NAN;
const char* iter = line;
int n = 0;
while (sscanf(iter, "%lf %n", &value, &n) != EOF) {
iter += n;
row->values = realloc(row->values, sizeof(double) * ++row->n);
row->values[row->n - 1] = value;
char format[16];
snprintf(format, sizeof(format) / sizeof(char), " %%*[%c] %%n", del);
sscanf(iter, format, &n);
iter += n;
}
return EXIT_SUCCESS;
}
/// @brief Read numeric values stored in a csv-format
/// @param filepath input file containing the numeric values
/// @param table table to be read into (must be empty)
/// @param del delimiter between individual values in a row
/// @return integral values signalling success or failure
static int iueio_loadtxt(const char* filepath, struct Table* table, char del, char comment) {
// check if table is empty
assert(table->n == 0);
// open file
FILE* stream = fopen(filepath, "r");
if (stream == NULL)
return EXIT_FAILURE;
// read from stream row-by-row (fixed size buffer)
static char line[1024];
// read each line into a row
while (fgets(&line[0], sizeof(line) / sizeof(char), stream)) {
if (line[0] == comment)
continue;
struct Row row = {NULL, 0};
int n = row_deserialize(&row, line, del);
table_append_move(table, &row);
}
fclose(stream);
return EXIT_SUCCESS;
}