home / secrets / src / core / store.c

store.c



//
//  store.c
//  secrets
//
//  Created by Anders on 09/07/2020.
//

#include <stdlib.h>
#include <string.h>
#include "store.h"
#include "../util/stringu.h"
#include "../util/require.h"
#include "../util/inputu.h"

#define BUFFER_SIZE 8192

static Entry *entries;
static uint32_t size;

static Entry* get(const char *key) {
    for(uint32_t i = 0; i < size; ++i) {
        if (stringu_equals(entries[i].key, key)) {
            return &entries[i];
        }
    }
    return NULL;
}

const Entry* store_get(const char *key) {
    return get(key);
}

const Entry* store_by_index(uint32_t index) {
    if (index >= size) return NULL;
    return &entries[index];
}

uint32_t store_size(void) {
  return size;
}

static void validate_key(const char *key) {
    char* illegal_char = strchr(key, '|');
    require(illegal_char == NULL, "key cannot contain '|' character");
}

void store_put(const char *key, const char* description, const char *value) {
    validate_key(key);
    Entry *found = get(key);
    if (found != NULL) {
        free(found->value);
        free(found->description);
        found->description = stringu_copy_alloc(description);
        found->value = stringu_copy_alloc(value);
    }
    else {
        uint32_t index = size;
        size++;
        entries = realloc(entries, size * sizeof(*entries));
        entries[index].key = stringu_copy_alloc(key);
        entries[index].description = stringu_copy_alloc(description);
        entries[index].value = stringu_copy_alloc(value);
    }
}

void store_init(const char* filename) {
    
    FILE *file = fopen(filename, "r");
    if (file == NULL) return;

    char buffer[BUFFER_SIZE];
    
    while(input_fgets(buffer, BUFFER_SIZE, file)) {
        stringu_trim(buffer);
        
        char* splitpoint = strchr(buffer, '|');
        if (splitpoint == NULL) continue;;
        
        char* split[3];
        stringu_split(buffer, split, "|");
        stringu_trim(split[0]);
        stringu_trim(split[1]);
        stringu_trim(split[2]);
        
        const char* key = split[0];
        validate_key(key);
        const char* description = split[1];
        const char* value = split[2];
        store_put(key, description, value);
    }
    fclose(file);
}

static void save_to_file(const char* filename) {
    remove(filename);
    
    FILE *file = fopen(filename, "w");
    for (uint32_t i = 0; i < size; ++i) {
        fprintf(file, "%s|%s|%s\n", entries[i].key, entries[i].description, entries[i].value);
    }
    fclose(file);
}

void store_persist(const char* filename) {
    save_to_file(filename);
}

void store_destroy(void) {
    free(entries);
}