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

refactoring: added libbdc/bdc_io, bdc_strings, bdc_hashtable and bdc_logging

parent 61c038fe
No related branches found
No related tags found
No related merge requests found
Showing
with 1173 additions and 174 deletions
......@@ -32,7 +32,11 @@ 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 "")
......@@ -40,6 +44,10 @@ 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_hashtable
bdc_io
bdc_logging
bdc_memory
bdc_strings
bdc_time)
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
//
// string_converters.h
// test_bdc_hashtable.c
//
// Copyright (C) 2011-2024, University of Vienna and Vienna Institute for Nature Conservation & Analyses, Andreas Gattringer.
//
......@@ -19,21 +20,33 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include <stdint.h>
#ifndef CATS_STRING_CONVERTERS_H
#define CATS_STRING_CONVERTERS_H
bool string_to_float(char *string, float *value);
bool string_to_bool(char *string, bool *value);
bool string_to_double(char *string, double *value);
bool string_to_integer(char *string, int32_t *value);
bool string_to_long_double(char *string, long double *value);
#endif //CATS_STRING_CONVERTERS_H
#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,13 +55,7 @@ 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';
......
// SPDX-License-Identifier: GPL-3.0-or-later
//
// io_text.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_IO_TEXT_H
#define CATS_IO_TEXT_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
#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 "bdc_time/bdc_time.h"
#include "misc/misc.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 bdc_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 bdc_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 (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 (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 (bdc_log_file != NULL) fprintf(bdc_log_file, "%s%s%s\n", color, msg, C_RESET);
return;
}
const char *log_default = "unknown";
......@@ -223,54 +218,59 @@ 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 (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);
} 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_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 (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 (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 "bdc_time/bdc_time.h"
#if defined(__MINGW32__) || defined(CATS_ON_WINDOWS)
#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 bdc_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,9 +174,16 @@ 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);
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;
}
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
......@@ -19,10 +19,11 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include "cats_global.h"
#include <inttypes.h>
#include "cats_strings.h"
#include "logging/logging.h"
#include "bdc_strings.h"
#include "bdc_logging/logging.h"
void print_string(int indent, const char *name, const char *value)
{
......@@ -32,7 +33,7 @@ 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)
{
indent *= 2;
if (indent > 0) log_message(LOG_RAW, "%*s", indent, "");
......
......@@ -25,8 +25,10 @@
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include "string_converters.h"
#include "logging/logging.h"
#include "bdc_logging/logging.h"
const char *true_values[] = {"1", "y", "t"};
const char *false_values[] = {"0", "n", "f"};
......@@ -34,7 +36,7 @@ const int true_counts = (int) (sizeof(true_values) / sizeof(char *));
const int false_counts = (int) (sizeof(false_values) / sizeof(char *));
bool string_to_double(char *string, double *value)
bool string_to_double(const char *string, double *value)
{
if (string == NULL || strlen(string) == 0) return false;
......@@ -82,7 +84,7 @@ bool string_to_float(char *string, float *value)
}
bool string_to_long_double(char *string, long double *value)
bool string_to_long_double(const char *string, long double *value)
{
if (string == NULL || strlen(string) == 0) return false;
......@@ -127,7 +129,7 @@ bool string_to_bool(char *string, bool *value)
}
bool string_to_integer(char *string, int32_t *value)
bool string_to_integer(const char *string, int32_t *value)
{
if (string == NULL || strlen(string) == 0) return false;
......@@ -148,3 +150,7 @@ bool string_to_integer(char *string, int32_t *value)
return false;
}
......@@ -19,12 +19,11 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include "cats_global.h"
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <logging/logging.h>
#include "bdc_logging/logging.h"
#include "bdc_memory/bdc_memory.h"
......@@ -78,6 +77,13 @@ char *left_trim(char *line)
}
char *trim_both(char *line)
{
return left_trim(right_trim(line));
}
size_t substring_count(const char *haystack, const char *needle)
{
size_t count = 0;
......@@ -134,8 +140,8 @@ char *replace_substring(const char *original, const char *search, const char *re
exit(EXIT_FAILURE);
}
size_t occurrences = substring_count(original, search);
size_t result_len = strlen(original) + strlen(replacement) * occurrences - strlen(search) * occurrences + 1;
size_t n_occurrences = substring_count(original, search);
size_t result_len = strlen(original) + strlen(replacement) * n_occurrences - strlen(search) * n_occurrences + 1;
char *result = calloc_or_die(1, result_len);
......@@ -144,20 +150,24 @@ char *replace_substring(const char *original, const char *search, const char *re
size_t bytes_copied = 0;
for (size_t i = 0; i < occurrences; i++) {
for (size_t i = 0; i < n_occurrences; i++) {
char *next_occurrence = strstr(orig_loc, search);
if (next_occurrence == NULL) { break; }
if (next_occurrence == NULL || strlen(next_occurrence) == 0) { break; }
// how many bytes are before our first hit?
size_t bytes_to_copy = strlen(orig_loc) - strlen(next_occurrence);
if (bytes_to_copy) {
bytes_copied += bytes_to_copy;
strncpy(result_loc, orig_loc, bytes_to_copy);
result_loc += bytes_to_copy;
orig_loc += bytes_to_copy + search_len;
orig_loc += bytes_to_copy;
}
strncpy(result_loc, replacement, replacement_len);
result_loc += replacement_len;
orig_loc += search_len;
}
if (bytes_copied < original_len) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment