Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • development
  • main
  • refactor-libraries
  • 1.0.0
  • 1.0.1
  • 1.0.2
  • 1.0.3
  • 1.1.0
8 results

Target

Select target project
  • bdc/cats
1 result
Select Git revision
  • development
  • main
  • refactor-libraries
  • 1.0.0
  • 1.0.1
  • 1.0.2
  • 1.0.3
  • 1.1.0
8 results
Show changes
Commits on Source (3)
Showing
with 1185 additions and 176 deletions
......@@ -30,12 +30,24 @@ else ()
MESSAGE("Unknown compiler: ${CMAKE_C_COMPILER_ID}")
endif ()
add_subdirectory(bdc_cross_platform)
add_subdirectory(bdc_hashtable)
add_subdirectory(bdc_io)
add_subdirectory(bdc_logging)
add_subdirectory(bdc_memory)
add_subdirectory(bdc_strings)
add_subdirectory(bdc_time)
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_memory)
bdc_hashtable
bdc_io
bdc_logging
bdc_memory
bdc_strings
bdc_time)
add_library(bdc_cross_platform STATIC)
target_sources(bdc_cross_platform
PRIVATE
bdc_cross_platform.c
PUBLIC
bdc_cross_platform.h)
set_property(TARGET bdc_cross_platform PROPERTY POSITION_INDEPENDENT_CODE ON)
\ No newline at end of file
// SPDX-License-Identifier: GPL-3.0-or-later
//
// io_text.h
// bdc_cross_platform.c
//
// Copyright (C) 2011-2024, University of Vienna and Vienna Institute for Nature Conservation & Analyses, Andreas Gattringer.
//
......@@ -19,8 +19,3 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef CATS_IO_TEXT_H
#define CATS_IO_TEXT_H
#endif
// SPDX-License-Identifier: GPL-3.0-or-later
//
// string_converters.h
// bdc_cross_platform.h
//
// Copyright (C) 2011-2024, University of Vienna and Vienna Institute for Nature Conservation & Analyses, Andreas Gattringer.
//
......@@ -19,21 +19,40 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef BDC_WINDOWS_H
#define BDC_WINDOWS_H
#include <stdint.h>
#ifdef WIN32
#define BDC_ON_WINDOWS
#endif
#if defined(__MINGW64__) || defined(__MINGW32__)
#define __USE_MINGW_ANSI_STDIO 1
#endif
#ifdef BDC_ON_WINDOWS
#define strncasecmp strnicmp
#define strcasecmp stricmp
#define strtok_r strtok_s
#define access _access
#define F_OK 0
#include <string.h>
#include <bdc_memory/bdc_memory.h>
#ifndef CATS_STRING_CONVERTERS_H
#define CATS_STRING_CONVERTERS_H
bool string_to_float(char *string, float *value);
static inline char *strndup(const char *s, size_t n)
{
char *end_pointer = memchr(s, '\0', n);
if (end_pointer != NULL) {
n = end_pointer - s;
}
bool string_to_bool(char *string, bool *value);
char *result = malloc_or_die(n + 1);
memcpy(result, s, n);
result[n] = '\0';
return result;
}
bool string_to_double(char *string, double *value);
#endif
bool string_to_integer(char *string, int32_t *value);
bool string_to_long_double(char *string, long double *value);
#endif //CATS_STRING_CONVERTERS_H
#endif //BDC_WINDOWS_H
add_library(bdc_hashtable STATIC bdc_hashtable.c bdc_hashtable.h)
set_property(TARGET bdc_hashtable PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(bdc_hashtable bdc_logging)
add_executable(bdc_hashtable_test tests/test_bdc_hashtable.c)
target_link_libraries(bdc_hashtable_test bdc_strings)
\ No newline at end of file
// SPDX-License-Identifier: GPL-3.0-or-later
//
// bdc_hashtable.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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "bdc_hashtable.h"
#include "bdc_logging/logging.h"
#include "bdc_memory/bdc_memory.h"
struct bdc_value {
union {
char *string;
int64_t int64;
double double_value;
void *pointer;
};
enum bdc_value_type type;
};
struct bdc_item {
char *key;
struct bdc_value *value;
struct bdc_item *next;
};
struct bdc_hash_table {
size_t item_count;
size_t bucket_count;
size_t *items_per_bucket;
//size_t max_items_pro_bucket;
struct bdc_item **items;
};
// FNV-1a hash, see https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash
#define OFFSET 14695981039346656037UL
#define PRIME 1099511628211UL
#define DEBUG(...)
// FIXME: add function to return keys
uint64_t hash_function(const char *key)
{
uint64_t hash = OFFSET;
while (*key != '\0') {
hash ^= (uint64_t) (unsigned char) *key;
hash *= PRIME;
key++;
}
return hash;
}
__attribute__((unused)) size_t hash_index(const char *key, size_t buckets)
{
return (size_t) hash_function(key) & (buckets - 1);
}
size_t hash_idx_from_hash(uint64_t hash, size_t buckets)
{
return hash & (buckets - 1);
}
struct bdc_hash_table *bdc_intern_new_hash_table(size_t buckets)
{
struct bdc_hash_table *table = calloc_or_die(1, sizeof(struct bdc_hash_table));
table->bucket_count = buckets;
table->items = calloc_or_die(table->bucket_count, sizeof(struct bdc_item *));
table->item_count = 0;
//table->max_items_pro_bucket = 0;
table->items_per_bucket = calloc_or_die(table->bucket_count, sizeof(size_t));
DEBUG("Creating hash table with %lu buckets\n", table->bucket_count)
for (size_t i = 0; i < table->bucket_count; i++) {
table->items_per_bucket[i] = 0;
table->items[i] = NULL;
}
return table;
}
__attribute__((unused)) struct bdc_hash_table *new_hash_table(void)
{
return bdc_intern_new_hash_table(MIN_SIZE);
}
void destroy_value(struct bdc_value **value)
{
if (value == NULL || *value == NULL) return;
struct bdc_value *this = *value;
if(this->type == BDC_STRING) {
log_message(LOG_DEBUG, "freeing string value '%s'", this->string);
free(this->string);
this->string = NULL;
}
log_message(LOG_DEBUG, "freeing value");
free(this);
*value = NULL;
}
struct bdc_item *bdc_intern_get_entry(struct bdc_hash_table *table, const char *key, uint64_t hash)
{
size_t hash_idx = hash_idx_from_hash(hash, table->bucket_count);
if (table->items[hash_idx] == NULL) return NULL;
struct bdc_item *entry = table->items[hash_idx];
if (0 == strcmp(entry->key, key)) return entry;
while (entry->next != NULL) {
entry = entry->next;
if (0 == strcmp(entry->key, key)) return entry;
}
return NULL;
}
struct bdc_item *get_entry(struct bdc_hash_table *table, const char *key)
{
uint64_t hash = hash_function(key);
size_t hash_idx = hash & (table->bucket_count - 1);
if (table->items[hash_idx] == NULL) return NULL;
struct bdc_item *entry = table->items[hash_idx];
if (0 == strcmp(entry->key, key)) return entry;
while (entry->next != NULL) {
entry = entry->next;
if (0 == strcmp(entry->key, key)) return entry;
}
return NULL;
}
void destroy_item(struct bdc_item **item)
{
if(item == NULL || *item == NULL) return;
struct bdc_item *this = *item;
destroy_value(&this->value);
free(this->key);
free(this);
*item = NULL;
}
bool remove_key(struct bdc_hash_table *table, const char *key)
{
if (!bdc_key_in_hash_table(table, key)) return false;
uint64_t hash = hash_function(key);
size_t hash_idx = hash & (table->bucket_count - 1);
struct bdc_item *target = NULL;
struct bdc_item *entry = table->items[hash_idx];
if (0 == strcmp(entry->key, key)) {
target = entry;
table->items[hash_idx] = target->next;
table->items_per_bucket[hash_idx]--;
destroy_item(&target);
return true;
}
struct bdc_item *prev = NULL;
while (entry->next != NULL) {
prev = entry,
entry = entry->next;
if (0 == strcmp(entry->key, key)) {
target = entry;
prev->next = target->next;
table->items_per_bucket[hash_idx]--;
free(entry);
return true;
}
}
return false;
}
__attribute__((unused)) bool bdc_key_in_hash_table(struct bdc_hash_table *table, const char *key)
{
return get_entry(table, key) != NULL;
}
struct bdc_value *bdc_get_value_from_key(struct bdc_hash_table *table, const char *key)
{
struct bdc_item *entry = get_entry(table, key);
if (entry) {
return entry->value;
} else {
return NULL;
}
}
struct bdc_item *new_entry(const char *key, struct bdc_value *value)
{
struct bdc_item *entry = calloc_or_die(1, sizeof(struct bdc_item));
entry->value = value;
log_message(LOG_DEBUG, "duplicating key '%s'", key);
entry->key = strdup(key);
entry->next = NULL;
return entry;
}
void print_key_val(struct bdc_item *entry)
{
struct bdc_value *value = entry->value;
switch (value->type) {
case BDC_STRING:
printf("\t\t%s -> '%s'\n", entry->key, value->string);
break;
case BDC_INT64:
printf("\t\t%s -> %ld\n", entry->key, value->int64);
break;
case BDC_DOUBLE:
printf("\t\t%s -> %f\n", entry->key, value->double_value);
break;
case BDC_CUSTOM:
printf("\t\t%s -> %p\n", entry->key, value->pointer);
break;
}
}
__attribute__((unused)) void print_hash_table(const struct bdc_hash_table *table)
{
printf("\n");
printf("Hash table: %lu buckets with %lu items\n", table->bucket_count,
table->item_count);
for (size_t i = 0; i < table->bucket_count; i++) {
if (table->items[i] == NULL) continue;
printf("\tentry %lu: %lu entries\n", i, table->items_per_bucket[i]);
size_t count = 1;
struct bdc_item *entry = table->items[i];
print_key_val(entry);
while (entry->next != NULL) {
entry = entry->next;
count++;
print_key_val(entry);
}
if (count != table->items_per_bucket[i]) {
printf("Error: mismatch between expected (%lu) and found entries (%lu)\n",
table->items_per_bucket[i], i);
}
}
printf("\n");
}
struct bdc_item *bdc_intern_add_entry(struct bdc_hash_table *table, struct bdc_item *entry, uint64_t hash)
{
size_t hash_idx = hash_idx_from_hash(hash, table->bucket_count);
entry->next = table->items[hash_idx];
table->items[hash_idx] = entry;
table->items_per_bucket[hash_idx] += 1;
table->item_count += 1;
return entry;
}
void rehash_table(struct bdc_hash_table *table)
{
log_message(LOG_INFO, "%s: rehashing!", __func__);
struct bdc_hash_table *tmp = bdc_intern_new_hash_table(table->bucket_count * 2);
for (size_t i = 0; i < table->bucket_count; i++) {
if (table->items[i] == NULL) continue;
struct bdc_item *entry = table->items[i];
struct bdc_item *next = entry->next;
uint64_t hash = hash_function(entry->key);
bdc_intern_add_entry(tmp, entry, hash);
while (next) {
entry = next;
next = entry->next;
hash = hash_function(entry->key);
bdc_intern_add_entry(tmp, entry, hash);
}
}
free(table->items);
free(table->items_per_bucket);
table->items = tmp->items;
table->items_per_bucket = tmp->items_per_bucket;
table->bucket_count = tmp->bucket_count;
free(tmp);
tmp = NULL;
}
struct bdc_item *bdc_ht_add_string(struct bdc_hash_table *table, const char *key, const char *value)
{
struct bdc_value *val = calloc(1, sizeof(struct bdc_value));
log_message(LOG_DEBUG, "duplicating value '%s", value);
val->string = strdup(value);
val->type = BDC_STRING;
return intern_bdc_add_entry(table, key, val);
}
struct bdc_item *bdc_ht_add_custom(struct bdc_hash_table *table, const char *key, void *value)
{
struct bdc_value *val = calloc(1, sizeof(struct bdc_value));
val->pointer = value;
val->type = BDC_CUSTOM;
return intern_bdc_add_entry(table, key, val);
}
struct bdc_item *bdc_ht_add_int64(struct bdc_hash_table *table, const char *key, int64_t value)
{
struct bdc_value *val = calloc(1, sizeof(struct bdc_value));
val->int64 = value;
val->type = BDC_INT64;
return intern_bdc_add_entry(table, key, val);
}
struct bdc_item *bdc_ht_add_double(struct bdc_hash_table *table, const char *key, double value)
{
struct bdc_value *val = calloc(1, sizeof(struct bdc_value));
val->double_value = value;
val->type = BDC_DOUBLE;
return intern_bdc_add_entry(table, key, val);
}
struct bdc_item *intern_bdc_add_entry(struct bdc_hash_table *table, const char *key, struct bdc_value *value)
{
uint64_t hash = hash_function(key);
size_t hash_idx = hash_idx_from_hash(hash, table->bucket_count);
switch (value->type) {
case BDC_STRING:
log_message(LOG_DEBUG, "adding entry %s %s with hash %lu to bucket %lu", key, value->string,
hash_function(key), hash_idx);
break;
case BDC_INT64:
log_message(LOG_DEBUG, "adding entry %s %ld with hash %lu to bucket %lu", key, value->int64,
hash_function(key), hash_idx);
break;
case BDC_DOUBLE:
log_message(LOG_DEBUG, "adding entry %s %f with hash %lu to bucket %lu", key,
value->double_value,
hash_function(key), hash_idx);
break;
case BDC_CUSTOM:
log_message(LOG_DEBUG, "adding entry %s %p with hash %lu to bucket %lu", key, value->pointer,
hash_function(key), hash_idx);
break;
}
struct bdc_item *entry = bdc_intern_get_entry(table, key, hash);
if (entry != NULL) {
log_message(LOG_DEBUG, "replacing key '%s'", entry->key);
destroy_value(&entry->value);
entry->value = value;
if (entry->value->type == BDC_STRING) {
log_message(LOG_DEBUG, "setting value of '%s' to '%s'", key, entry->value->string);
}
return entry;
}
assert(entry == NULL);
entry = new_entry(key, value);
bdc_intern_add_entry(table, entry, hash);
if (table->items_per_bucket[hash_idx] > 2) {
rehash_table(table);
}
log_message(LOG_DEBUG, "added key '%s'\n", key);
return entry;
}
bool bdc_ht_get_int64_from_key(struct bdc_hash_table *table, const char *key, int64_t *result)
{
struct bdc_value *value = bdc_get_value_from_key(table, key);
if (!value) return false;
if (value->type != BDC_INT64) return false;
*result = value->int64;
return true;
}
__attribute__((unused)) bool bdc_ht_get_double_from_key(struct bdc_hash_table *table, const char *key, double *result)
{
struct bdc_value *value = bdc_get_value_from_key(table, key);
if (!value) return false;
if (value->type != BDC_DOUBLE) return false;
*result = value->double_value;
return true;
}
bool bdc_ht_get_string_from_key(struct bdc_hash_table *table, const char *key, char **result)
{
struct bdc_value *value = bdc_get_value_from_key(table, key);
if (!value) return false;
if (value->type != BDC_STRING) return false;
*result = strdup(value->string);
return true;
}
void destroy_hash_table(struct bdc_hash_table **ht)
{
if (ht == NULL || *ht == NULL) return;
struct bdc_hash_table *t = *ht;
size_t count = t->bucket_count;
for (size_t i = 0; i < count; i++){
struct bdc_item *item = t->items[i];
while(item){
struct bdc_item *this = item;
item = item->next;
if (this->value->type == BDC_STRING) {
log_message(LOG_DEBUG, "freeing item '%s' -> '%s'", this->key, this->value->string);
free(this->value->string);
}
free(this->value);
free(this->key);
free(this);
this = NULL;
}
free(item);
}
free(t->items_per_bucket);
free(t->items);
free(t);
*ht = NULL;
}
\ No newline at end of file
// SPDX-License-Identifier: GPL-3.0-or-later
//
// bdc_hashtable.h
//
// 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.
//
#ifndef BDC_HASHTABLE_H
#define BDC_HASHTABLE_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#define MIN_SIZE 1024
enum bdc_value_type {
BDC_STRING = 0,
BDC_INT64 = 1,
BDC_DOUBLE = 2,
BDC_CUSTOM
};
struct bdc_hash_table;
struct bdc_value;
bool remove_key(struct bdc_hash_table *table, const char *key);
struct bdc_item *intern_bdc_add_entry(struct bdc_hash_table *table, const char *key, struct bdc_value *value);
struct bdc_item *bdc_ht_add_string(struct bdc_hash_table *table, const char *key, const char *value);
struct bdc_item *bdc_ht_add_custom(struct bdc_hash_table *table, const char *key, void *custom);
struct bdc_item *bdc_ht_add_int64(struct bdc_hash_table *table, const char *key, int64_t value);
struct bdc_item *bdc_ht_add_double(struct bdc_hash_table *table, const char *key, double value);
__attribute__((unused)) struct bdc_hash_table *new_hash_table(void);
__attribute__((unused)) void print_hash_table(const struct bdc_hash_table *table);
struct bdc_value *bdc_get_value_from_key(struct bdc_hash_table *table, const char *key);
__attribute__((unused)) bool bdc_key_in_hash_table(struct bdc_hash_table *table, const char *key);
bool bdc_ht_get_int64_from_key(struct bdc_hash_table *table, const char *key, int64_t *result);
bool bdc_ht_get_string_from_key(struct bdc_hash_table *table, const char *key, char **result);
__attribute__((unused)) bool bdc_ht_get_double_from_key(struct bdc_hash_table *table, const char *key, double *result);
void destroy_hash_table(struct bdc_hash_table **ht);
#define bdc_ht_get_data_from_key(TABLE, KEY, RESULT) _GENERIC((RESULT), \
int64_t *: bdc_ht_get_int64_from_key, \
char **: bdc_ht_get_string_from_key, \
double *: bdc_ht_get_value_from_key, \
)(TABLE, KEY, (RESULT))
#define bdc_ht_add_entry(table, key, value) \
_Generic((value),\
int64_t: bdc_ht_add_int64, \
int: bdc_ht_add_int64, \
double: bdc_ht_add_double, \
void *: bdc_ht_add_custom, \
char *: bdc_ht_add_string)(table, key, value)
// move to private later // FIXME
void rehash_table(struct bdc_hash_table *table);
#endif //BDC_HASHTABLE_H
// SPDX-License-Identifier: GPL-3.0-or-later
//
// test_bdc_hashtable.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 <stdlib.h>
#include "bdc_hashtable/bdc_hashtable.h"
#include "bdc_strings/bdc_strings.h"
int main(int argc, char **argv)
{
//logging_initialize(LOG_DEBUG, NULL, NULL, false);
struct bdc_hash_table *t = new_hash_table();
bdc_ht_add_string(t, "a", "b12345");
bdc_ht_add_string(t, "a", "c123123");
bdc_ht_add_string(t, "b", "d21542");
bdc_ht_add_string(t, "c", "d316315");
bdc_ht_add_string(t, "d", "d1326536");
bdc_ht_add_string(t, "a", "d316136");
remove_key(t, "a");
bdc_ht_add_string(t, "a", "e13616136136");
destroy_hash_table(&t);
struct string_substitution *s = new_substituter();
add_substitution(s, "%a", "<was a>");
add_substitution(s, "%b", "<was b>");
add_substitution(s, "%c", "<was c>");
const char *orig = "%c-%a-%b-%c-aa-%d";
char *x = substitute_string(orig, s);
printf("%s -> %s\n", orig, x);
destroy_substituter(&s);
free(x);
return 0;
}
\ No newline at end of file
add_library(bdc_io STATIC "" ../bdc_cross_platform/bdc_cross_platform.h )
target_sources(bdc_io
PRIVATE
bdc_io.c
bdc_paths.c
PUBLIC
bdc_io.h
)
set_property(TARGET bdc_io PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(bdc_io bdc_strings)
// SPDX-License-Identifier: GPL-3.0-or-later
//
// io_text.c
// bdc_io.c
//
// Copyright (C) 2011-2024, University of Vienna and Vienna Institute for Nature Conservation & Analyses, Andreas Gattringer.
//
......@@ -19,13 +19,12 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include "cats_global.h"
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <logging/logging.h>
#include "cats_strings.h"
#include "bdc_memory/bdc_memory.h"
#include "bdc_io.h"
char *read_single_line(FILE *file)
{
......@@ -33,9 +32,9 @@ char *read_single_line(FILE *file)
char buffer[MAX_STRING_BUFF_LENGTH] = {0};
fgets(buffer, MAX_STRING_BUFF_LENGTH, file);
fflush(stdout);
char *result = right_trim(buffer);
if (strlen(result)) return strdup(result);
if (strlen(buffer)) return strdup(buffer);
return NULL;
}
......@@ -47,7 +46,7 @@ char *slurp_file(const char *filename)
FILE *file = fopen(filename, "r");
if (!file) {
log_message(LOG_ERROR, "%s: File '%s' does not exist or could not be opened.", __func__, filename);
fprintf(stderr, "%s: File '%s' does not exist or could not be opened.\n", __func__, filename);
return NULL;
}
......@@ -56,15 +55,9 @@ char *slurp_file(const char *filename)
long size = ftell(file);
fseek(file, 0L, SEEK_SET);
char *buffer = malloc(size + 1);
if (!buffer) {
log_message(LOG_ERROR, "%s: failed to allocate memory", __func__);
exit(EXIT_FAILURE);
}
char *buffer = malloc_or_die(size + 1);
fread(buffer, sizeof(char), size, file);
fclose(file);
buffer[size] = '\0';
return buffer;
}
}
\ No newline at end of file
// SPDX-License-Identifier: GPL-3.0-or-later
//
// string_helpers.h
// bdc_io.h
//
// Copyright (C) 2011-2024, University of Vienna and Vienna Institute for Nature Conservation & Analyses, Andreas Gattringer.
//
......@@ -19,8 +19,38 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef CATS_STRING_HELPERS_H
#define CATS_STRING_HELPERS_H
#ifndef BDC_IO_H
#define BDC_IO_H
#define MAX_STRING_BUFF_LENGTH 4096
#if defined(WIN32) || defined (_WIN32)
#define DIRECTORY_SEPARATOR "\\"
#else
#define DIRECTORY_SEPARATOR "/"
#endif
#endif //CATS_STRING_HELPERS_H
#include "bdc_strings/bdc_strings.h"
char *slurp_file(const char *filename);
char *read_single_line(FILE *file);
#define ENSURE_FILE_OPENED(FILE_HANDLE, FILENAME)\
if (! (FILE_HANDLE))\
{\
fprintf(stderr, "ERROR: Couldn't open file %s in %s: %d (%s)\n", FILENAME, __FILE__, __LINE__, __func__);\
exit(EXIT_FAILURE);\
}
char *assemble_path(const struct string_array *path);
char *assemble_filename(struct string_array *path, struct string_array *filename, char *field_separator, char *extension);
bool check_and_create_directory_if_needed(const struct string_array *directory_path);
bool directory_exists(const char *path);
bool directory_writable(const char *path);
void make_directory(const char *path);
#endif //BDC_IO_H
// SPDX-License-Identifier: GPL-3.0-or-later
//
// bdc_paths.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 <string.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include "bdc_io.h"
#include "bdc_cross_platform/bdc_cross_platform.h"
#ifdef BDC_ON_WINDOWS
#include <direct.h>
#else
#include <unistd.h>
#endif
bool directory_exists(const char *path)
{
struct stat info;
int rc = stat(path, &info);
if (rc == 0 && info.st_mode & S_IFDIR) return true;
if (rc == 0) {
fprintf(stderr, "Path '%s' is not a directory. Exiting.\n", path);
exit(EXIT_FAILURE);
}
fprintf(stderr, "Directory '%s' does not exist\n", path);
return false;
}
bool directory_writable(const char *path)
{
int rc = access(path, F_OK);
if (rc == 0) {
return true;
}
fprintf(stderr, "directory %s exists but cannot be accessed or written to.\n", path);
return false;
}
void make_directory(const char *path)
{
#ifndef BDC_ON_WINDOWS
int rc = mkdir(path, S_IRWXU);
#else
int rc = _mkdir(path);
#endif
if (rc == 0) return;
int error = errno;
fprintf(stderr, "unable to create directory %s: %s\n", path, strerror(error));
exit(EXIT_FAILURE);
}
char *assemble_path(const struct string_array *path)
{
return string_array_paste(path, DIRECTORY_SEPARATOR);
}
char *
assemble_filename(struct string_array *path, struct string_array *filename, char *field_separator, char *extension)
{
char *name_string = string_array_paste(filename, field_separator);
char *result = NULL;
if (path && get_string_count(path) > 0) {
char *path_string = string_array_paste(path, DIRECTORY_SEPARATOR);
if (extension && strlen(extension)) {
char *fn = compound_string(name_string, extension, ".");
result = compound_string(path_string, fn, DIRECTORY_SEPARATOR);
free(fn);
} else {
result = compound_string(path_string, name_string, DIRECTORY_SEPARATOR);
}
free(path_string);
} else {
if (extension && strlen(extension)) {
result = compound_string(name_string, extension, ".");
} else {
result = strdup(name_string);
}
}
free(name_string);
return result;
}
bool check_and_create_directory_if_needed(const struct string_array *directory_path)
{
if (directory_path == NULL || get_string_count(directory_path) == 0) {
fprintf(stderr, "Unable to check directory - no path specified\n");
exit(EXIT_FAILURE);
}
char *dir = assemble_path(directory_path);
if (!directory_exists(dir)) {
fprintf(stderr, "directory '%s' does not exist. Trying to create.\n", dir);
make_directory(dir);
}
bool writeable = directory_writable(dir);
free(dir);
return writeable;
}
\ No newline at end of file
add_library(cats_logging STATIC "" ../cats_windows.h)
add_library(bdc_logging STATIC "")
target_sources(cats_logging
target_sources(bdc_logging
PRIVATE
../cats_defs.h
logging.c
PUBLIC
logging.h
)
target_include_directories(cats_logging PUBLIC ".")
set_property(TARGET cats_logging PROPERTY POSITION_INDEPENDENT_CODE ON)
\ No newline at end of file
target_include_directories(bdc_logging PUBLIC ".")
target_link_libraries(bdc_logging bdc_memory bdc_time bdc_cross_platform)
set_property(TARGET bdc_logging PROPERTY POSITION_INDEPENDENT_CODE ON)
\ No newline at end of file
# bdc_logging
This is a library to handle logging.
## Dependencies
* bdc_memory
* bdc_time
* bdc_cross_platform (header only)
......@@ -21,27 +21,26 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include "logging.h"
#include "bdc_memory/bdc_memory.h"
#include "cats_time/cats_time.h"
#include "misc/misc.h"
#include "bdc_memory/bdc_memory.h"
#include "bdc_time/bdc_time.h"
#include "bdc_io/bdc_io.h"
#include "bdc_logging/logging.h"
enum cats_log_level internal_current_log_level = LOG_INFO;
enum bdc_log_level internal_current_log_level = LOG_INFO;
int32_t logging_mpi_rank = -1;
struct cats_time cats_logging_start_time;
FILE *cats_log_file = NULL;
char *cats_log_file_name = NULL;
struct bdc_time bdc_logging_start_time;
FILE *bdc_log_file = NULL;
char *bdc_log_file_name = NULL;
const char *logging_module_name = NULL;
bool time_initialized = false;
bool logging_quiet = false;
const char *get_log_level_name(enum cats_log_level level)
const char *get_log_level_name(enum bdc_log_level level)
{
switch (level) {
case LOG_DEBUG:
......@@ -50,7 +49,6 @@ const char *get_log_level_name(enum cats_log_level level)
return "INFO";
case LOG_RAW:
case LOG_EMPTY:
return "";
case LOG_MARK:
return "";
case LOG_IMPORTANT:
......@@ -70,58 +68,52 @@ const char *get_log_level_name(enum cats_log_level level)
}
const char *get_log_level_color(enum cats_log_level level)
const char *get_log_level_color(enum bdc_log_level level)
{
switch (level) {
case LOG_RAW:
case LOG_DEBUG:
return C_RESET;
case LOG_INFO:
return C_RESET;
case LOG_EMPTY:
return C_RESET;
case LOG_MARK:
return C_RESET;
case LOG_IMPORTANT:
return C_YELLOW;
case LOG_WARNING:
return C_YELLOW;
case LOG_ERROR:
return C_RED;
case LOG_MPI:
return C_RED;
case LOG_UNIMPLEMENTED:
return C_RED;
case LOG_UNKNOWN:
return C_RED;
}
return C_RESET;
}
void set_log_level(enum cats_log_level new_level)
void set_log_level(enum bdc_log_level new_level)
{
internal_current_log_level = new_level;
}
// - mpi world rank can be added later
// FIXME: if start_time is NULL, generate
void logging_initialize(enum cats_log_level level, const struct cats_time *start_time, const char *log_file_name, bool quiet)
void
logging_initialize(enum bdc_log_level level, const struct bdc_time *start_time, const char *log_file_name, bool quiet)
{
set_log_level(level);
logging_quiet = quiet;
if (start_time != NULL) {
cats_logging_start_time = *start_time;
bdc_logging_start_time = *start_time;
time_initialized = true;
}
if (log_file_name != NULL) {
cats_log_file_name = strdup(log_file_name);
cats_log_file = fopen(log_file_name, "w");
ENSURE_FILE_OPENED(cats_log_file, cats_log_file_name)
bdc_log_file_name = strdup(log_file_name);
bdc_log_file = fopen(log_file_name, "w");
ENSURE_FILE_OPENED(bdc_log_file, bdc_log_file_name)
}
}
......@@ -138,13 +130,16 @@ void logging_set_mpi_rank(int mpi_world_rank)
logging_mpi_rank = mpi_world_rank;
}
// actual logging function(s), only to be called from log_message
void log_msg(const char *msg, enum cats_log_level loglevel);
void log_msg_simple(const char *msg, enum cats_log_level loglevel);
void log_msg(const char *msg, enum bdc_log_level loglevel);
void log_msg_simple(const char *msg, enum bdc_log_level loglevel);
// logging wrapper function
__attribute__ ((__format__ (__printf__, 2, 3)))
void log_message(enum cats_log_level level, const char *fmt, ...)
void log_message(enum bdc_log_level level, const char *fmt, ...)
{
if (level < internal_current_log_level) return;
......@@ -165,13 +160,13 @@ void log_message(enum cats_log_level level, const char *fmt, ...)
}
enum cats_log_level get_log_level(void)
enum bdc_log_level get_log_level(void)
{
return internal_current_log_level;
}
void log_message_simple(enum cats_log_level level, const char *fmt, ...)
__attribute__((unused)) void log_message_simple(enum bdc_log_level level, const char *fmt, ...)
{
if (level < internal_current_log_level) return;
char *message = NULL;
......@@ -190,26 +185,26 @@ void log_message_simple(enum cats_log_level level, const char *fmt, ...)
}
void log_msg(const char *msg, enum cats_log_level loglevel)
void log_msg(const char *msg, enum bdc_log_level loglevel)
{
if (loglevel < internal_current_log_level) return;
if (loglevel == LOG_RAW) {
if (! logging_quiet) fprintf(stdout, "%s", msg);
if (cats_log_file != NULL) fprintf(cats_log_file, "%s", msg);
if (!logging_quiet) fprintf(stdout, "%s", msg);
if (bdc_log_file != NULL) fprintf(bdc_log_file, "%s", msg);
return;
}
if (loglevel == LOG_EMPTY) {
if (! logging_quiet) fprintf(stdout, "\n");
if (cats_log_file != NULL) fprintf(cats_log_file, "\n");
if (!logging_quiet) fprintf(stdout, "\n");
if (bdc_log_file != NULL) fprintf(bdc_log_file, "\n");
return;
}
const char *color = get_log_level_color(loglevel);
if (loglevel == LOG_MARK) {
if (! logging_quiet) fprintf(stdout, "%s%s%s\n", color, msg, C_RESET);
if (cats_log_file != NULL) fprintf(cats_log_file, "%s%s%s\n", color, msg, C_RESET);
if (!logging_quiet) fprintf(stdout, "%s%s%s\n", color, msg, C_RESET);
if (bdc_log_file != NULL) fprintf(bdc_log_file, "%s%s%s\n", color, msg, C_RESET);
return;
}
const char *log_default = "unknown";
......@@ -222,55 +217,60 @@ void log_msg(const char *msg, enum cats_log_level loglevel)
if (logging_mpi_rank >= 0) {
if (! logging_quiet) fprintf(stdout, "(%02d)::", logging_mpi_rank);
if (cats_log_file != NULL) fprintf(cats_log_file, "(%02d)::", logging_mpi_rank);
if (!logging_quiet) fprintf(stdout, "(%02d)::", logging_mpi_rank);
if (bdc_log_file != NULL) fprintf(bdc_log_file, "(%02d)::", logging_mpi_rank);
}
if (time_initialized) {
double secs = seconds_monotonic_since(&cats_logging_start_time);
if (cats_log_file != NULL) {
fprintf(cats_log_file, "% 16.4f::", secs);
double secs = seconds_monotonic_since(&bdc_logging_start_time);
if (bdc_log_file != NULL) {
fprintf(bdc_log_file, "% 16.4f::", secs);
}
if (! logging_quiet) fprintf(stdout, "% 16.4f::", secs);
if (!logging_quiet) fprintf(stdout, "% 16.4f::", secs);
} else {
if (cats_log_file != NULL) {
fprintf(cats_log_file, " ::");
if (bdc_log_file != NULL) {
fprintf(bdc_log_file, " ::");
}
if (! logging_quiet) fprintf(stdout, " ::");
if (!logging_quiet) fprintf(stdout, " ::");
}
if (logging_module_name != NULL) {
if (! logging_quiet) fprintf(stdout, "%s%s::[%s] %s%s\n", color, loglevel_name, logging_module_name, msg, C_RESET);
if (cats_log_file) fprintf(cats_log_file, "%s%s::[%s] %s%s\n", color, loglevel_name, logging_module_name, msg, C_RESET);
if (!logging_quiet)
fprintf(stdout, "%s%s::[%s] %s%s\n", color, loglevel_name, logging_module_name, msg, C_RESET);
if (bdc_log_file)
fprintf(bdc_log_file, "%s%s::[%s] %s%s\n", color, loglevel_name, logging_module_name, msg,
C_RESET);
} else {
if (! logging_quiet) fprintf(stdout, "%s%s::%s%s\n", color, loglevel_name, msg, C_RESET);
if (cats_log_file) fprintf(cats_log_file, "%s%s::%s%s\n", color, loglevel_name, msg, C_RESET);
if (!logging_quiet) fprintf(stdout, "%s%s::%s%s\n", color, loglevel_name, msg, C_RESET);
if (bdc_log_file) fprintf(bdc_log_file, "%s%s::%s%s\n", color, loglevel_name, msg, C_RESET);
}
}
void log_msg_simple(const char *msg, enum cats_log_level loglevel)
void log_msg_simple(const char *msg, enum bdc_log_level loglevel)
{
if (loglevel < internal_current_log_level) return;
const char *log_default = "unknown";
const char *loglevel_name = log_default;
if (loglevel <= LOG_UNKNOWN && loglevel >= LOG_DEBUG) {
if (loglevel <= LOG_UNKNOWN) {
loglevel_name = get_log_level_name(loglevel);
}
const char *color = get_log_level_color(loglevel);
if (logging_mpi_rank >= 0) {
if (! logging_quiet) fprintf(stdout, "(%02d)%s%s: %s%s", logging_mpi_rank, color, loglevel_name, msg, C_RESET);
if (cats_log_file != NULL) fprintf(cats_log_file, "(%02d)%s%s: %s%s", logging_mpi_rank, color, loglevel_name, msg, C_RESET);
if (!logging_quiet)
fprintf(stdout, "(%02d)%s%s: %s%s", logging_mpi_rank, color, loglevel_name, msg, C_RESET);
if (bdc_log_file != NULL)
fprintf(bdc_log_file, "(%02d)%s%s: %s%s", logging_mpi_rank, color, loglevel_name, msg,
C_RESET);
} else {
if (! logging_quiet) fprintf(stdout, "%s%s::%s%s\n", color, loglevel_name, msg, C_RESET);
if (cats_log_file != NULL) fprintf(cats_log_file, "%s%s::%s%s\n", color, loglevel_name, msg, C_RESET);
if (!logging_quiet) fprintf(stdout, "%s%s::%s%s\n", color, loglevel_name, msg, C_RESET);
if (bdc_log_file != NULL) fprintf(bdc_log_file, "%s%s::%s%s\n", color, loglevel_name, msg, C_RESET);
}
}
......@@ -19,14 +19,15 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef CATS_LOGGING_H_
#define CATS_LOGGING_H_
#ifndef BDC_LOGGING_H_
#define BDC_LOGGING_H_
#include <stdbool.h>
#include "cats_defs.h"
#include <time.h>
#include "cats_time/cats_time.h"
#if defined(__MINGW32__) || defined(CATS_ON_WINDOWS)
#include "bdc_time/bdc_time.h"
#if defined(__MINGW32__) || defined(WIN32)
// no color codes
#define C_RED ""
#define C_GREEN ""
......@@ -41,7 +42,7 @@
#define C_WHITE "\x1B[37m"
#endif
enum cats_log_level {
enum bdc_log_level {
LOG_DEBUG,
LOG_INFO,
LOG_EMPTY,
......@@ -55,19 +56,25 @@ enum cats_log_level {
LOG_UNKNOWN
};
void logging_initialize(enum cats_log_level level, const struct cats_time *start_time, const char *log_file_name, bool quiet);
void
logging_initialize(enum bdc_log_level level, const struct bdc_time *start_time, const char *log_file_name, bool quiet);
void logging_set_mpi_rank(int mpi_world_rank);
void logging_set_module_name(const char *name);
__attribute__ ((__format__ (__printf__, 2, 3)))
void log_message(enum cats_log_level level, const char *fmt, ...);
void log_message(enum bdc_log_level level, const char *fmt, ...);
enum bdc_log_level get_log_level(void);
__attribute__((unused)) void log_message_simple(enum bdc_log_level level, const char *fmt, ...);
enum cats_log_level get_log_level(void);
void set_log_level(enum bdc_log_level new_level);
void log_message_simple(enum cats_log_level level, const char *fmt, ...);
#define INCOMPLETE_IMPLEMENTATION() log_message(LOG_ERROR, "%s: not yet implemented", __func__)
#define MISSING_IMPLEMENTATION(X) log_message(LOG_ERROR, "%s: missing functionality %s", __func__, (X))
#define ABORT_IMPLEMENTATION() log_message(LOG_ERROR, "%s:%s:%d: not yet implemented", __FILE__, __func__, __LINE__); exit(EXIT_FAILURE)
void set_log_level(enum cats_log_level new_level);
#endif
\ No newline at end of file
add_library(bdc_strings STATIC "" ../bdc_cross_platform/bdc_cross_platform.h
)
target_sources(bdc_strings
PRIVATE
bdc_strings.c
pretty_print.c
string_helpers.c
string_substitution.c
string_converters.c
PUBLIC
bdc_strings.h
)
set_property(TARGET bdc_strings PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(bdc_strings bdc_logging bdc_hashtable)
\ No newline at end of file
# bdc_strings
This is a library to handle strings.
## Dependencies
* bdc_logging
* bdc_hashtable
// SPDX-License-Identifier: GPL-3.0-or-later
//
// cats_strings.c
// bdc_strings.c
//
// Copyright (C) 2011-2024, University of Vienna and Vienna Institute for Nature Conservation & Analyses, Andreas Gattringer.
//
......@@ -19,24 +19,57 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include "cats_global.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cats_strings.h"
#include <logging/logging.h>
#include "bdc_strings.h"
#include "bdc_logging/logging.h"
#include "bdc_memory/bdc_memory.h"
#include <assert.h>
struct string_array {
int count;
char **string;
enum JSON_HINT *typehint;
};
void asprintf_check(int rc)
{
if (rc >= 0) return;
log_message(LOG_ERROR, "error in asprintf_ could not allocate memory or other error. rc: %d", rc);
log_message(LOG_ERROR, "error in asprintf - could not allocate memory or other error. rc: %d", rc);
exit(EXIT_FAILURE);
}
void snprintf_check(int rc, size_t expected)
{
if (rc >= 0 && (rc == expected || rc + 1 == expected)) return;
if (rc < 0) {
log_message(LOG_ERROR, "error in snprintf - error : %d", rc);
exit(EXIT_FAILURE);
}
if (rc < expected - 1) {
log_message(LOG_DEBUG, "error in snprintf - output truncated: %d of %ld bytes written", rc, expected);
}
}
int get_string_count(const struct string_array *array)
{
assert(array != NULL);
return array->count;
}
const char *get_string(const struct string_array *array, int count)
{
assert(array != NULL);
assert(count >= 0);
assert(count < array->count);
return array->string[count];
}
void string_array_add(struct string_array *array, const char *string)
{
if (!array) {
......@@ -51,6 +84,8 @@ void string_array_add(struct string_array *array, const char *string)
DBG_STRING(log_message(LOG_RAW, "%s: address: %p\n", __func__, array);)
DBG_STRING(log_message(LOG_RAW, "%s: count: %d\n", __func__, array->count);)
DBG_STRING(log_message(LOG_RAW, "%s: trying to add: %s\n", __func__, string);)
DBG_STRING(log_message(LOG_RAW, "%p: string address: %p\n", __func__, array->string);)
DBG_STRING(log_message(LOG_RAW, "%s: new size: %zu\n", __func__, new_size);)
array->string = realloc_or_die(array->string, new_size);
array->typehint = realloc_or_die(array->typehint, sizeof(enum JSON_HINT) * (array->count + 1));
......@@ -66,7 +101,7 @@ void string_array_add(struct string_array *array, const char *string)
}
void string_array_add_conditional(struct string_array *array, char *string, bool condition)
__attribute__((unused)) void string_array_add_conditional(struct string_array *array, char *string, bool condition)
{
if (!condition) return;
string_array_add(array, string);
......@@ -79,8 +114,10 @@ void string_array_add_int(struct string_array *array, int32_t number, const char
if (!format_string || !strlen(format_string)) f = "%d";
int count = snprintf(NULL, 0, f, number) + 1;
snprintf_check(count, -1);
char *tmp = malloc_or_die(count);
snprintf(tmp, count, f, number);
int rc = snprintf(tmp, count, f, number);
snprintf_check(rc, count);
string_array_add(array, tmp);
array->typehint[array->count - 1] = JSON_NUMERIC;
......@@ -94,6 +131,7 @@ void string_array_add_int64(struct string_array *array, int64_t number, char *fo
if (!format_string || !strlen(format_string)) f = "%ld";
int count = snprintf(NULL, 0, f, number) + 1;
snprintf_check(count, -1);
char *tmp = malloc_or_die(count);
snprintf(tmp, count, f, number);
......@@ -103,20 +141,22 @@ void string_array_add_int64(struct string_array *array, int64_t number, char *fo
}
void string_array_add_double(struct string_array *array, double number, const char *format_string)
__attribute__((unused)) void string_array_add_double(struct string_array *array, double number, const char *format_string)
{
const char *f = format_string;
if (!format_string || !strlen(format_string)) f = "%f";
int count = snprintf(NULL, 0, f, number) + 1;
snprintf_check(count, -1);
char *tmp = malloc_or_die(count);
snprintf(tmp, count, f, number);
int rc = snprintf(tmp, count, f, number);
snprintf_check(rc, count);
string_array_add(array, tmp);
array->typehint[array->count - 1] = JSON_NUMERIC;
free(tmp);
}
void
__attribute__((unused)) void
string_array_add_int_conditional(struct string_array *array, int32_t number, const char *format_string, bool condition)
{
if (!condition) return;
......@@ -134,11 +174,18 @@ struct string_array *new_string_array()
return result;
}
const char *get_nth_string_from_array(const struct string_array *array, int n)
__attribute__((unused)) const char *string_array_get_string(const struct string_array *array, int n)
{
if (array == NULL || array->string == NULL) {
log_message(LOG_ERROR, "%s: string array or contents are NULL", __func__);
exit(EXIT_FAILURE);
}
assert(array != NULL);
if (n < 0 && n >= array->count) {
log_message(LOG_ERROR, "%s: requested string index %d out of range [0, %d]", __func__ , n, array->count);
log_message(LOG_ERROR, "%s: requested string index %d out of range [0, %d]", __func__, n, array->count);
exit(EXIT_FAILURE);
}
......@@ -146,6 +193,7 @@ const char *get_nth_string_from_array(const struct string_array *array, int n)
}
struct string_array *new_string_array_init(const char *entry)
{
struct string_array *result = new_string_array();
......@@ -207,16 +255,16 @@ int32_t count_fields(const char *line, const char *sep)
// untested trivial
void abort_on_null_token(const char *token, char *orig, int count)
void abort_on_null_token(const char *token, const char *orig, int count)
{
if (token != NULL) return;
log_message(LOG_WARNING, "%s: string '%s' has not enough (%d) tokens", __func__, orig, count);
abort();
exit(EXIT_FAILURE);
//exit(EXIT_FAILURE);
}
struct string_array *get_all_tokens(char *line, const char *sep)
struct string_array *get_all_tokens(const char *line, const char *sep)
{
const int32_t max_count = count_fields(line, sep);
......@@ -229,6 +277,7 @@ struct string_array *get_all_tokens(char *line, const char *sep)
char *token = strtok_r(copy, sep, &saveptr);
abort_on_null_token(token, line, max_count);
char *to_add = strdup(token);
to_add = left_trim(right_trim(to_add));
string_array_add(result, to_add);
......@@ -253,7 +302,7 @@ struct string_array *get_all_tokens(char *line, const char *sep)
}
char *get_nth_token(char *line, const char *sep, int32_t n)
__attribute__((unused)) char *get_nth_token(char *line, const char *sep, int32_t n)
{
char *result = NULL;
struct string_array *tokens = get_all_tokens(line, sep);
......@@ -265,7 +314,7 @@ char *get_nth_token(char *line, const char *sep, int32_t n)
}
char *remove_0th_token(char *line, const char *sep)
char *remove_0th_token(const char *line, const char *sep)
{
char *result = NULL;
struct string_array *tokens = get_all_tokens(line, sep);
......@@ -302,7 +351,7 @@ char *json_dict(const struct string_array *header, const struct string_array *da
char *result = calloc_or_die(1, len);
size_t written = 0;
size_t written; // = 0;
result[0] = '{'; // written: 1
written = 1;
......@@ -361,7 +410,7 @@ char *string_array_paste(const struct string_array *array, const char *sep)
if (length == 0) {
log_message(LOG_ERROR, "%s: empty string, exiting", __func__);
abort();
exit(EXIT_FAILURE);
// exit(EXIT_FAILURE);
}
length += (array->count - 1) * strlen(sep); // space for separator
......@@ -382,7 +431,7 @@ char *string_array_paste(const struct string_array *array, const char *sep)
}
void print_string_array(const struct string_array *array)
__attribute__((unused)) void print_string_array(const struct string_array *array)
{
log_message(LOG_RAW, "string array with %d entries:\n", array->count);
for (int32_t i = 0; i < array->count; i++) {
......@@ -392,7 +441,7 @@ void print_string_array(const struct string_array *array)
}
int32_t string_array_index(const struct string_array *array, const char *needle)
__attribute__((unused)) int32_t string_array_string_index(const struct string_array *array, const char *needle)
{
if (array == NULL) {
log_message(LOG_ERROR, "%s: called with empty parameter array", __func__);
......@@ -407,7 +456,7 @@ int32_t string_array_index(const struct string_array *array, const char *needle)
}
bool in_string_array(const struct string_array *array, const char *needle)
__attribute__((unused)) bool string_array_contains_string(const struct string_array *array, const char *needle)
{
for (int32_t i = 0; i < array->count; i++) {
if (strcmp(needle, array->string[i]) == 0) return true;
......@@ -442,6 +491,20 @@ char *compound_string(const char *s1, const char *s2, const char *sep)
size_t len = strlen(s1) + strlen(s2) + strlen(sep) + 1;
result = malloc_or_die(len);
snprintf(result, len, "%s%s%s", s1, sep, s2);
//printf("s1: %s (%ld)\n", s1, strlen(s1));
//printf("sep: %s (%ld)\n", sep, strlen(sep));
//printf("s2: %s (%ld)\n", s2, strlen(s2));
//printf("len: %ld\n", len);
int rc = snprintf(result, len, "%s%s%s", s1, sep, s2);
//printf("res: %s (%ld)\n", result, strlen(result));
snprintf_check(rc, len);
return result;
}
\ No newline at end of file
}
bool string_is_empty_or_null(const char *name)
{
if (name == NULL) return true;
if (strlen(name) == 0) return true; // FIXME CHECK ONLY FIRST X BYTES
return false;
}
// SPDX-License-Identifier: GPL-3.0-or-later
//
// cats_strings.h
// bdc_strings.h
//
// Copyright (C) 2011-2024, University of Vienna and Vienna Institute for Nature Conservation & Analyses, Andreas Gattringer.
//
......@@ -21,51 +21,44 @@
#ifndef CATS_STRING_H_
#define CATS_STRING_H_
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include "data/error.h"
#include <stdio.h>
struct string_array;
struct string_substitution;
enum JSON_HINT {
JSON_STRING = 0,
JSON_QUOTED = 0,
JSON_UNQUOTED = 1,
JSON_NUMERIC = 1
};
// constants
#define TEXT_DIVIDER "=================================================================================================="
#define PAD_NAME 55
#define PAD_VALUE 35
struct string_array {
int count;
char **string;
enum JSON_HINT *typehint;
};
#include <stdio.h>
#define MAX_STRING_BUFF_LENGTH 2048
char *read_single_line(FILE *file);
char *slurp_file(const char *filename);
//#define DEBUG_STRING
#ifdef DEBUG_STRING
#define DBG_STRING(X) {X;}while(0);
#else
#define DBG_STRING(X)
#endif
#define ENSURE_FILE_OPENED(FILE_HANDLE, FILENAME)\
if (! (FILE_HANDLE))\
{\
fprintf(stderr, "ERROR: Couldn't open file %s in %s: %d (%s)\n", FILENAME, __FILE__, __LINE__, __func__);\
exit(E_UNREADABLE_FILE);\
}
// string array functions
struct string_array *new_string_array(void);
void asprintf_check(int rc);
const char *get_string(const struct string_array *array, int count);
struct string_array *new_string_array(void);
int get_string_count(const struct string_array *array);
void free_string_array(struct string_array **array);
int32_t count_fields(const char *line, const char *sep);
struct string_array *get_all_tokens(const char *line, const char *sep);
struct string_array *get_all_tokens(char *line, const char *seperator);
void string_array_add(struct string_array *array, const char *string);
......@@ -73,33 +66,42 @@ void string_array_add_int64(struct string_array *array, int64_t number, char *fo
char *string_array_paste(const struct string_array *array, const char *sep);
char *assemble_filename(struct string_array *path, struct string_array *filename, char *filesep, char *extension);
void string_array_add_int(struct string_array *array, int32_t number, const char *format_string);
struct string_array *new_string_array_init(const char *entry);
void string_array_add_conditional(struct string_array *array, char *string, bool conditon);
__attribute__((unused)) void string_array_add_conditional(struct string_array *array, char *string, bool conditon);
void string_array_add_double(struct string_array *array, double number, const char *format_string);
__attribute__((unused)) void string_array_add_double(struct string_array *array, double number, const char *format_string);
void
__attribute__((unused)) void
string_array_add_int_conditional(struct string_array *array, int32_t number, const char *format_string, bool condition);
const char *get_nth_string_from_array(const struct string_array *array, int n);
void print_string_array(const struct string_array *array);
char *remove_0th_token(char *line, const char *sep);
__attribute__((unused)) const char *string_array_get_string(const struct string_array *array, int n);
__attribute__((unused)) void print_string_array(const struct string_array *array);
char *get_nth_token(char *line, const char *sep, int32_t n);
struct string_array *copy_string_array(const struct string_array *src);
char *json_dict(const struct string_array *header, const struct string_array *data);
int32_t string_array_index(const struct string_array *array, const char *needle);
int32_t string_array_string_index(const struct string_array *array, const char *needle);
__attribute__((unused)) bool string_array_contains_string(const struct string_array *array, const char *needle);
// string functions
char *trim_both(char *line);
int32_t count_fields(const char *line, const char *sep);
bool in_string_array(const struct string_array *array, const char *needle);
char *remove_0th_token(const char *line, const char *sep);
__attribute__((unused)) char *get_nth_token(char *line, const char *sep, int32_t n);
size_t substring_count(const char *haystack, const char *needle);
......@@ -115,14 +117,20 @@ char *right_trim(char *line);
char *left_trim(char *line);
void abort_on_null_token(const char *token, char *orig, int count);
bool string_is_empty_or_null(const char *name);
#define PAD_NAME 55
#define PAD_VALUE 35
void abort_on_null_token(const char *token, const char *orig, int count);
// helper functions
void asprintf_check(int rc);
void snprintf_check(int rc, size_t expected);
// pretty print functions
void print_string(int indent, const char *name, const char *value);
void print_subcategory(int indent, const char *category_name, int64_t category_number, char *name);
void print_subcategory(int indent, const char *category_name, int64_t category_number, const char *name);
void print_category(int indent, const char *category, const char *name);
......@@ -130,15 +138,38 @@ void print_integer(int indent, const char *name, int64_t value);
void print_rate(int indent, const char *name, long double value);
// string substitution
void add_substitution(struct string_substitution *substituter, const char *key, const char *initial_value);
void update_substitution(struct string_substitution *substituter, const char *key, const char *initial_value);
struct string_substitution *new_substituter(void);
char *substitute_string(const char *string, const struct string_substitution *substituter);
void destroy_substituter(struct string_substitution **substituter);
struct string_substitution *copy_substituter(const struct string_substitution *from);
void add_substitution_integer(struct string_substitution *substituter, const char *key, int32_t initial_value);
void set_integer_pattern(struct string_substitution *substituter, const char *key, const char *pattern);
// conversion function
const char *bool_to_string(bool b);
#ifdef DEBUG_STRING
#define DBG_STRING(X) {X;}while(0);
#else
#define DBG_STRING(X)
#endif
bool string_to_float(char *string, float *value);
bool string_to_bool(char *string, bool *value);
bool string_to_double(const char *string, double *value);
// implemented in string_helpers.h
bool string_to_integer(const char *string, int32_t *value);
bool string_to_long_double(const char *string, long double *value);
#endif