Skip to content
Snippets Groups Projects
Commit 8f3ebced authored by Andreas Gattringer's avatar Andreas Gattringer
Browse files

refactoring: added libbdc/bdc_csv

parent 4da5e4b8
No related branches found
No related tags found
No related merge requests found
......@@ -32,6 +32,7 @@ endif ()
add_subdirectory(bdc_cross_platform)
add_subdirectory(bdc_csv)
add_subdirectory(bdc_hashtable)
add_subdirectory(bdc_io)
add_subdirectory(bdc_logging)
......@@ -44,6 +45,7 @@ add_library(bdc STATIC "")
set_target_properties(bdc PROPERTIES LINKER_LANGUAGE C)
set_property(TARGET bdc PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(bdc
bdc_csv
bdc_hashtable
bdc_io
bdc_logging
......
add_library(bdc_csv STATIC "" )
target_sources(bdc_csv
PRIVATE
bdc_csv.c
PUBLIC
bdc_csv.h
)
set_property(TARGET bdc_csv PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(bdc_csv bdc_logging bdc_memory bdc_strings bdc_io)
add_executable(bdc_csv_test tests/bdc_csv_link_test.c)
target_link_libraries(bdc_csv_test bdc_csv)
\ No newline at end of file
# bdc_csv
This is a library to load simple CSV (comma separated values) files from disk.
Field quoting is currently not implemented.
## Dependencies
* bdc_io
* bdc_logging
* bdc_memory
* bdc_strings
// SPDX-License-Identifier: GPL-3.0-or-later
//
// cats_csv.c
// bdc_csv.c
//
// Copyright (C) 2011-2024, University of Vienna and Vienna Institute for Nature Conservation & Analyses, Andreas Gattringer.
//
......@@ -19,19 +19,39 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include "cats_global.h"
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "cats_csv.h"
#include <bdc_logging/logging.h>
#include "bdc_logging/logging.h"
#include "bdc_memory/bdc_memory.h"
#include "bdc_csv.h"
#include "bdc_io/bdc_io.h"
struct bdc_csv {
int32_t data_row_count; ///< number of data rows in the CSV file (not including the header)
int32_t column_count; ///< number of data fields (columns) in the CSV file
char **headers; ///< array of headers with length \ref cats_csv.field_count -- NOTE: could be a string array
char ***data; ///< CSV data stored as strings by row and column
};
struct cats_csv *csv_new(char *header_line, int32_t expected_fields)
int32_t csv_row_count(const struct bdc_csv *csv)
{
assert(csv != NULL);
return csv->data_row_count;
}
int32_t csv_column_count(const struct bdc_csv *csv)
{
assert(csv != NULL);
return csv->column_count;
}
struct bdc_csv *csv_new(const char *header_line, int32_t expected_fields) // FIXME simple csv open file function
{
int32_t fields = count_fields(header_line, ",");
......@@ -49,7 +69,7 @@ struct cats_csv *csv_new(char *header_line, int32_t expected_fields)
exit(EXIT_FAILURE);
}
struct cats_csv *result = malloc_or_die_trace(sizeof(struct cats_csv), __func__);
struct bdc_csv *result = malloc_or_die_trace(sizeof(struct bdc_csv), __func__);
result->column_count = get_string_count(headers) ;
result->data_row_count = 0;
......@@ -65,9 +85,9 @@ struct cats_csv *csv_new(char *header_line, int32_t expected_fields)
}
void csv_free(struct cats_csv **csv)
void csv_free(struct bdc_csv **csv)
{
struct cats_csv *this = *csv;
struct bdc_csv *this = *csv;
if (!this) {
log_message(LOG_WARNING, "%s received empty struct - cannot free", __func__);
......@@ -104,72 +124,75 @@ void csv_free(struct cats_csv **csv)
}
int32_t csv_get_field_idx(struct cats_csv *csv, const char *field_name)
int32_t csv_get_column_idx(const struct bdc_csv *csv, const char *column_name)
{
assert(csv);
assert(field_name);
assert(column_name);
assert(csv->column_count >= 0);
int32_t column_idx = -1;
int32_t field_idx = -1;
for (int32_t i = 0; i < csv->column_count; i++) {
if (!strcmp(field_name, csv->headers[i])) {
field_idx = i;
if (!strcmp(column_name, csv->headers[i])) {
column_idx = i;
break;
}
}
if (field_idx < 0) {
log_message(LOG_ERROR, "%s: could not find field '%s' in csv\n", __func__, field_name);
if (column_idx < 0) {
log_message(LOG_ERROR, "%s: could not find field '%s' in csv\n", __func__, column_name);
exit(EXIT_FAILURE);
}
return field_idx;
return column_idx;
}
char *csv_get_value_field_name(struct cats_csv *csv, int32_t row, const char *field_name) // untested indirect
char *csv_get_row_entry_from_column_name(const struct bdc_csv *csv, int32_t row, const char *field_name) // untested indirect
{
assert(csv);
assert(row >= 0);
assert(row <= csv->data_row_count);
int32_t field_idx = csv_get_field_idx(csv, field_name);
int32_t field_idx = csv_get_column_idx(csv, field_name);
if (row > csv->data_row_count) {
log_message(LOG_ERROR, "%s: invalid row number %d, csv has %d rows\n", __func__, row,
csv->data_row_count);
exit(EXIT_FAILURE);
}
assert(row <= csv->data_row_count);
return csv->data[row][field_idx];
}
char *csv_get_value_field_idx(struct cats_csv *csv, int32_t row, int32_t field_idx) // untested indirect
char *csv_get_row_entry_from_column_idx(const struct bdc_csv *csv, int32_t row, int32_t field_idx) // untested indirect
{
assert(csv);
assert(row >= 0);
assert(field_idx >= 0);
if (field_idx < 0 || field_idx > csv->column_count) {
log_message(LOG_ERROR, "%s: invalid field index %d, csv has %d fields\n", __func__, field_idx,
csv->column_count);
exit(EXIT_FAILURE);
}
assert(field_idx >= 0);
if (row > csv->data_row_count || row < 0) {
log_message(LOG_ERROR, "%s: invalid row index %d, csv has %d rows\n", __func__, row,
csv->data_row_count);
exit(EXIT_FAILURE);
}
assert(row >= 0);
return csv->data[row][field_idx];
}
double csv_get_double_field_name(struct cats_csv *csv, int32_t row, const char *field_name) // untested indirect
double csv_get_double_from_column_name(const struct bdc_csv *csv, int32_t row, const char *field_name) // untested indirect
{
char *string = csv_get_value_field_name(csv, row, field_name);
const char *string = csv_get_row_entry_from_column_name(csv, row, field_name);
double value = NAN;
bool success = string_to_double(string, &value);
if (!success) {
......@@ -181,24 +204,24 @@ double csv_get_double_field_name(struct cats_csv *csv, int32_t row, const char *
}
double csv_get_double_field_idx(struct cats_csv *csv, int32_t row, int32_t field_idx) // untested indirect
double csv_get_double_value_from_column_index(const struct bdc_csv *csv, int32_t row, int32_t column_idx) // untested indirect
{
char *string = csv_get_value_field_idx(csv, row, field_idx);
const char *string = csv_get_row_entry_from_column_idx(csv, row, column_idx);
double value = NAN;
bool success = string_to_double(string, &value);
if (!success) {
log_message(LOG_ERROR, "error converting %s to floating point number!", string);
log_message(LOG_ERROR, "error converting '%s' to floating point number!", string);
exit(EXIT_FAILURE);
}
return value;
}
int32_t csv_get_int32_field_idx(struct cats_csv *csv, int32_t row, int32_t field_idx) // untested indirect
int32_t csv_get_int32_value_from_column_index(const struct bdc_csv *csv, int32_t row, int32_t column_idx) // untested indirect
{
char *string = csv_get_value_field_idx(csv, row, field_idx);
const char *string = csv_get_row_entry_from_column_idx(csv, row, column_idx);
int32_t value = INT32_MIN;
bool success = string_to_integer(string, &value);
......@@ -210,7 +233,7 @@ int32_t csv_get_int32_field_idx(struct cats_csv *csv, int32_t row, int32_t field
}
void csv_add_row(struct cats_csv *csv, char *line)
void csv_add_row(struct bdc_csv *csv, const char *line)
{
if (strlen(line) == 0) return; // ignore empty line
if (line[0] == '#') return; // ignore comment line
......@@ -250,28 +273,30 @@ void csv_add_row(struct cats_csv *csv, char *line)
}
struct cats_csv *csv_from_filename(const char *filename, int expected_fields)
struct bdc_csv *csv_from_filename(const char *filename, int expected_fields)
{
FILE *f = fopen(filename, "r");
ENSURE_FILE_OPENED(f, filename)
struct cats_csv *csv = csv_read_file(f, expected_fields);
struct bdc_csv *csv = csv_read_file(f, expected_fields);
fclose(f);
return csv;
}
struct cats_csv *csv_read_file(FILE *input, int expected_fields) // tested
struct bdc_csv *csv_read_file(FILE *input, int expected_fields) // tested
{
char *header_line = read_single_line(input);
struct cats_csv *csv = csv_new(header_line, expected_fields);
header_line = trim_both(header_line);
if (expected_fields < 0) {
expected_fields = count_fields(header_line, ",");
}
struct bdc_csv *csv = csv_new(header_line, expected_fields);
free(header_line);
char *line = NULL;
line = read_single_line(input);
char *line = trim_both(read_single_line(input));
while (line) {
csv_add_row(csv, line);
......
// SPDX-License-Identifier: GPL-3.0-or-later
//
// cats_csv.h
// bdc_csv.h
//
// Copyright (C) 2011-2024, University of Vienna and Vienna Institute for Nature Conservation & Analyses, Andreas Gattringer.
//
......@@ -19,40 +19,40 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef CATS_CSV_H_
#define CATS_CSV_H_
#ifndef BDC_CSV_H_
#define BDC_CSV_H_
#include <stdint.h>
#include <stdio.h>
#include <bdc_strings/bdc_strings.h>
#include "bdc_strings/bdc_strings.h"
///@brief Data structure for simple csv files
struct cats_csv {
int32_t data_row_count; ///< number of data rows in the CSV file (not including the header)
int32_t column_count; ///< number of data fields (columns) in the CSV file
char **headers; ///< array of headers with length \ref cats_csv.field_count -- NOTE: could be a string array
char ***data; ///< CSV data stored as strings by row and column
};
struct bdc_csv;
struct bdc_csv *csv_read_file(FILE *input, int expected_fields);
struct bdc_csv *csv_from_filename(const char *filename, int expected_fields);
struct cats_csv *csv_read_file(FILE *input, int expected_fields);
int32_t csv_row_count(const struct bdc_csv *csv);
int32_t csv_column_count(const struct bdc_csv *csv);
int32_t csv_get_field_idx(struct cats_csv *csv, const char *field_name);
int32_t csv_get_column_idx(const struct bdc_csv *csv, const char *column_name);
double csv_get_double_field_idx(struct cats_csv *csv, int32_t row, int32_t field_idx);
double csv_get_double_value_from_column_index(const struct bdc_csv *csv, int32_t row, int32_t column_idx);
int32_t csv_get_int32_field_idx(struct cats_csv *csv, int32_t row, int32_t field_idx);
int32_t csv_get_int32_value_from_column_index(const struct bdc_csv *csv, int32_t row, int32_t column_idx);
double csv_get_double_field_name(struct cats_csv *csv, int32_t row, const char *field_name);
double csv_get_double_from_column_name(const struct bdc_csv *csv, int32_t row, const char *field_name);
void csv_free(struct cats_csv **csv);
void csv_free(struct bdc_csv **csv);
struct cats_csv *csv_from_filename(const char *filename, int expected_fields);
#ifdef DEBUG_CSV
#define DBGCSV(X) {X} while(0);
#ifdef DEBUG_CSV_ENABLED
#define DBG_CSV(X) {X} while(0);
#else
#define DBGCSV(X);
#define DBG_CSV(X);
#endif
#endif
......
// SPDX-License-Identifier: GPL-3.0-or-later
//
// bdc_csv_link_test.c
//
// Copyright (C) 2011-2024, University of Vienna and Vienna Institute for Nature Conservation & Analyses, Andreas Gattringer.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include "bdc_csv/bdc_csv.h"
int main(int argc, char **argv) {
return 0;
}
\ No newline at end of file
add_subdirectory(cats)
add_subdirectory(cats_ini)
add_subdirectory(cats_csv)
add_subdirectory(modules/cats_test_module)
add_subdirectory(modules/butterflies)
\ No newline at end of file
......@@ -318,15 +318,15 @@ set(CATS_SOURCES_MPI
)
add_executable(cats cats.c)
target_link_libraries(libcats bdc_logging bdc bdc_strings cats_ini cats_csv)
target_link_libraries(cats libcats bdc_logging bdc bdc_strings cats_ini cats_csv)
target_link_libraries(libcats bdc_logging bdc bdc_strings cats_ini bdc_csv)
target_link_libraries(cats libcats bdc_logging bdc bdc_strings cats_ini bdc_csv)
if (MSVC)
# target_include_directories(cats PRIVATE ${GDAL_INCLUDE_DIRS})
# target_link_libraries(cats bdc_logging bdc_memory bdc_strings cats_ini cats_csv ${GDAL_LIBRARIES})
# target_link_libraries(cats bdc_logging bdc_memory bdc_strings cats_ini bdc_csv ${GDAL_LIBRARIES})
else ()
target_link_libraries(cats bdc_logging bdc bdc_strings cats_ini cats_csv)
target_link_libraries(cats bdc_logging bdc bdc_strings cats_ini bdc_csv)
endif ()
......@@ -334,7 +334,7 @@ if (MPI_FOUND)
add_executable(cats-mpi cats.c ${CATS_SOURCES_MPI})
target_link_libraries(cats-mpi ${MPI_C_LIBRARIES} bdc_logging bdc_memory bdc_strings cats_ini cats_csv libcats)
target_link_libraries(cats-mpi ${MPI_C_LIBRARIES} bdc_logging bdc_memory bdc_strings cats_ini bdc_csv libcats)
target_compile_options(cats-mpi PRIVATE -DUSEMPI)
......
......@@ -23,7 +23,7 @@
#define CATS_ENVIRONMENT_H
#include "cats_global.h"
#include "../../cats_csv/cats_csv.h"
#include "bdc_csv/bdc_csv.h"
#include "environment/glm.h"
#include "environment/environment_rasters.h"
......
......@@ -24,11 +24,13 @@
#include <math.h>
#include <assert.h>
#include "overlay_habitat_type_cc.h"
#include "cats_csv/cats_csv.h"
#include "logging.h"
#include "bdc_csv/bdc_csv.h"
#include "bdc_memory/bdc_memory.h"
#include "bdc_logging/logging.h"
#include "data/cats_datatypes.h"
#include "overlay_habitat_type_cc.h"
void cleanup_habitat_layer_cc_aux(void **data)
......@@ -47,7 +49,7 @@ void cleanup_habitat_layer_cc_aux(void **data)
struct habitat_layer_cc_aux *load_habitat_layer_cc_aux(const char *csv_file, double default_value)
{
struct cats_csv *csv = csv_from_filename(csv_file, 2);
struct bdc_csv *csv = csv_from_filename(csv_file, 2);
struct habitat_layer_cc_aux *result = calloc_or_die(1, sizeof(struct habitat_layer_cc_aux));
result->default_value = default_value;
......@@ -56,20 +58,20 @@ struct habitat_layer_cc_aux *load_habitat_layer_cc_aux(const char *csv_file, dou
}
int32_t key_field_idx = csv_get_field_idx(csv, "habitat_type");
int32_t value_field_idx = csv_get_field_idx(csv, "cc_multiplier");
int32_t key_field_idx = csv_get_column_idx(csv, "habitat_type");
int32_t value_field_idx = csv_get_column_idx(csv, "cc_multiplier");
int32_t min_key = INT32_MAX;
int32_t max_key = INT32_MIN;
double min_value = DBL_MAX;
double max_value = -DBL_MAX;
for (int32_t row = 0; row < csv->data_row_count; row++) {
int32_t key = csv_get_int32_field_idx(csv, row, key_field_idx);
const int32_t row_count = csv_row_count(csv);
for (int32_t row = 0; row < row_count; row++) {
int32_t key = csv_get_int32_value_from_column_index(csv, row, key_field_idx);
if (key < 0 || key >= MAX_HABITAT_TYPE_CODES) continue;
if (key < min_key) min_key = key;
if (key > max_key) max_key = key;
double value = csv_get_double_field_idx(csv, row, value_field_idx);
double value = csv_get_double_value_from_column_index(csv, row, value_field_idx);
if (value < min_value) min_value = value;
if (value > max_value) max_value = value;
result->habitat_multipliers[key] = value;
......
add_library(cats_csv STATIC "" )
target_sources(cats_csv
PRIVATE
../cats_defs.h
../cats_windows.h
cats_csv.c
PUBLIC
cats_csv.h
)
set_property(TARGET cats_csv PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(bdc_logging bdc bdc_strings)
\ No newline at end of file
......@@ -9,5 +9,5 @@ add_executable(vital_rate_test vital_rate_test.c)
add_executable(csv_test csv_test.c )
configure_file("test.csv" "test.csv")
target_link_libraries(vital_rate_test cmocka bdc_logging bdc bdc_strings cats_ini cats_csv libcats)
target_link_libraries(csv_test cmocka bdc_strings cats_csv bdc_strings bdc_logging bdc)
target_link_libraries(vital_rate_test cmocka bdc_logging bdc bdc_strings cats_ini bdc_csv libcats)
target_link_libraries(csv_test cmocka bdc_strings bdc_csv bdc_strings bdc_logging bdc)
......@@ -25,13 +25,13 @@
#include <stdio.h>
#include "bdc_memory/bdc_memory.h"
#include "bdc_strings/bdc_strings.h"
#include "cats_csv/cats_csv.h"
#include "bdc_csv/bdc_csv.h"
#include "bdc_io/bdc_io.h"
struct csv_test {
FILE *csv_file;
struct cats_csv *csv;
struct bdc_csv *csv;
};
#define CSV_FILE "test.csv"
......@@ -57,8 +57,8 @@ void test_csv_open(void **state)
assert_non_null(test->csv_file);
test->csv = csv_read_file(test->csv_file, 3);
assert_non_null(test->csv);
assert_int_equal(test->csv->data_row_count, 2);
assert_int_equal(test->csv->column_count, 3);
assert_int_equal(csv_row_count(test->csv), 2);
assert_int_equal(csv_column_count(test->csv), 3);
......@@ -67,10 +67,10 @@ void test_csv_open(void **state)
void test_read_csv(void **state)
{
struct csv_test *test = *state;
struct cats_csv *csv = test->csv;
double x0C = csv_get_double_field_name(csv, 0, "C");
int32_t col_B = csv_get_field_idx(csv, "B");
double x1B = csv_get_double_field_idx(csv, 1, 1);
struct bdc_csv *csv = test->csv;
double x0C = csv_get_double_from_column_name(csv, 0, "C");
int32_t col_B = csv_get_column_idx(csv, "B");
double x1B = csv_get_double_value_from_column_index(csv, 1, 1);
assert_true(col_B == 1);
assert_true(3.0 == x0C);
assert_true(5.0 == x1B);
......@@ -81,7 +81,7 @@ void test_read_csv(void **state)
void test_free_csv(void **state)
{
struct csv_test *test = *state;
struct cats_csv *csv = test->csv;
struct bdc_csv *csv = test->csv;
csv_free(&csv);
assert_null(csv);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment