143 lines
4.2 KiB
C
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;
|
|
} |