173 lines
4.7 KiB
C
173 lines
4.7 KiB
C
#include "../includes/matrix.h"
|
|
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
// Prints a debug view of a `matrix_t` to standard output.
|
|
void DebugPrintMatrix(matrix_t *matrix) {
|
|
printf("Grid ( len: %zu, head: %p ) { ", (matrix->len),
|
|
(void *)(matrix->head));
|
|
printf("data: [");
|
|
for (size_t i = 0; i < matrix->len; i++) {
|
|
if (i > 0) {
|
|
printf(", ");
|
|
} else {
|
|
printf(" ");
|
|
}
|
|
printf("%" PRImDATA, *(matrix->head + i));
|
|
}
|
|
printf("] }\n");
|
|
}
|
|
|
|
// Prints a row of a `matrix_t` to standard output.
|
|
void PrintMatrixRow(matrix_t *matrix, size_t row) {
|
|
for (size_t entry = 0; entry < matrix->row_len; entry++) {
|
|
printf("%" PRImDATA, *(matrix->head + row * (matrix->row_len) + entry));
|
|
if (entry != matrix->row_len - 1) {
|
|
printf(", ");
|
|
}
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
// Parameters for `increase_input_buffers`.
|
|
typedef struct {
|
|
size_t capacity;
|
|
data_t *head;
|
|
} matrix_bufs_t;
|
|
|
|
// Increases the data buffers used in `parse_input`.
|
|
//
|
|
// As reallocation will happen, the updated pointers and capacity are returned
|
|
// in an updated parameters object.
|
|
static matrix_bufs_t increase_input_buffers(matrix_bufs_t bufs) {
|
|
bufs.capacity *= 2;
|
|
bufs.head = realloc(bufs.head, bufs.capacity * sizeof(data_t));
|
|
if (bufs.head == NULL) {
|
|
printf(
|
|
"Failed to reallocate bigger buffer for input data. Was trying to "
|
|
"allocate %zu entries, aborting.",
|
|
bufs.capacity);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
return bufs;
|
|
}
|
|
|
|
// Compacts the allocated memory to fit exactly the number of elements.
|
|
static void compact_buffers(matrix_t *matrix) {
|
|
matrix->head = realloc(matrix->head, matrix->len * sizeof(data_t));
|
|
if ((matrix->head == NULL)) {
|
|
fprintf(stderr,
|
|
"Failed to reallocate matrix data buffers. Was trying to "
|
|
"allocate for %zu data entries, aborting.",
|
|
matrix->len);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
static data_t as_matrix_entry(char *str, size_t str_len) {
|
|
data_t value;
|
|
str[str_len] = 0; // Null-terminate the string.
|
|
int result = sscanf(str, "%" SCNmDATA, &value);
|
|
if (result == 0 || result == EOF) {
|
|
// Failed to parse this as an entry.
|
|
fprintf(stderr, "Cannot parse %s as a numerical matrix entry, aborting.",
|
|
str);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
// Parse a `matrix_t` by reading from standard input.
|
|
//
|
|
// We expect whitespace separated (possibly signed) integer values.
|
|
matrix_t ParseMatrix(size_t row_len) {
|
|
size_t capacity = 32; // Initial value is arbitrary.
|
|
size_t len = 0; // Number of entries stored.
|
|
data_t *head = malloc(capacity * sizeof(data_t));
|
|
|
|
_Bool spaces = 1;
|
|
char scanned;
|
|
char scan_str[50];
|
|
size_t scan_len = 0;
|
|
while (scanf("%c", &scanned) != EOF) {
|
|
if (isspace(scanned)) {
|
|
if (!spaces) {
|
|
// Finished reading string.
|
|
// Push the numerical entry into the matrix.
|
|
data_t value = as_matrix_entry(scan_str, scan_len);
|
|
head[len - 1] = value;
|
|
}
|
|
spaces = 1;
|
|
} else {
|
|
// A little input sanitization.
|
|
if (!(isdigit(scanned) || (scanned == '-'))) {
|
|
fprintf(
|
|
stderr,
|
|
"Foreign character %c (%x) found when processing input, aborting.",
|
|
scanned, scanned);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (spaces) {
|
|
// New string
|
|
len++;
|
|
scan_len = 0;
|
|
|
|
// Check if we need to resize the buffer.
|
|
if (len > capacity) {
|
|
matrix_bufs_t bufs = {
|
|
.capacity = capacity,
|
|
.head = head,
|
|
};
|
|
bufs = increase_input_buffers(bufs);
|
|
capacity = bufs.capacity;
|
|
head = bufs.head;
|
|
}
|
|
}
|
|
spaces = 0;
|
|
|
|
// Save the character to the entry string
|
|
scan_str[scan_len] = scanned;
|
|
scan_len++;
|
|
|
|
if (scan_len == 50) {
|
|
fprintf(stderr,
|
|
"An entry in the matrix is too long (over 50 characters).");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
} // End of scan loop
|
|
|
|
// Write the last entry if necessary
|
|
if (!spaces) {
|
|
data_t value = as_matrix_entry(scan_str, scan_len);
|
|
head[len - 1] = value;
|
|
}
|
|
|
|
// Input sanitization: confirm that the number of entries read is a multiple
|
|
// of the number of entries in a row.
|
|
if (!((len % row_len) == 0)) {
|
|
fprintf(stderr,
|
|
"Number of entries is not consistent with provided row length. "
|
|
"Got row length of %zu, and read %zu entries. Aborting.",
|
|
row_len, len);
|
|
// No need to free the buffers.
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
matrix_t matrix = {
|
|
.row_len = row_len,
|
|
.head = head,
|
|
.len = len,
|
|
};
|
|
|
|
compact_buffers(&matrix);
|
|
|
|
return matrix;
|
|
}
|
|
|
|
void MatrixFree(matrix_t *matrix) {
|
|
free(matrix->head);
|
|
} |