permanent-satori-hole/src/config/config_stream.c
2023-12-27 01:35:22 +01:00

160 lines
4.7 KiB
C

#include "config.h"
sat_config_ptr sat_config_stream_scope_to(sat_config_ptr ctx, char *prefix) {
int pfxLength = strlen(prefix);
bool appendColon = prefix[pfxLength - 1] != ':';
int length = pfxLength + 1;
if(appendColon) length += 1;
char *newPrefix = malloc(length);
memset(newPrefix, 0, length);
strcat(newPrefix, prefix);
if(appendColon) strcat(newPrefix, ":");
sat_config_ptr scoped = sat_config_alloc_scoped();
sat_config_scoped_ptr scopedInfo = (sat_config_scoped_ptr)scoped->info;
scopedInfo->parent = ctx;
scopedInfo->prefix = newPrefix;
return scoped;
}
char* sat_config_stream_read_value(sat_config_ptr ctx, char *name, char *fallback) {
sat_config_stream_ptr info = (sat_config_stream_ptr)ctx->info;
// this buffer is reasonable, you are not
char buffer[1024] = {0};
char *value = NULL;
// this buffer is also reasonable, you still aren't
// given this name is only used in strcmp and the index of the ending would be known
// there's honestly very little reason to not just replace the first trailing space
// with a \0 character and just passing buffer to strcmp
char cName[256] = {0};
int cNameLength;
// should retry for like 10 seconds
mtx_lock(info->lock);
fseek(info->stream, info->offset, SEEK_SET);
// probably do trimming later
while(fgets(buffer, sizeof buffer, info->stream) != NULL) {
if(buffer[0] == '\0' || buffer[0] == '\r' || buffer[0] == '\n'
|| buffer[0] == ' ' || buffer[0] == '#' || buffer[0] == ';')
continue;
// skip ridiculous lines too
if(buffer[(sizeof buffer) - 1] != '\0') {
memset(buffer, 0, sizeof buffer);
continue;
}
cNameLength = 0;
while(buffer[cNameLength] != ' ' && buffer[cNameLength] != '\0')
++cNameLength;
cName[cNameLength] = '\0';
memcpy(cName, buffer, cNameLength);
if(strcmp(cName, name) == 0) {
int valueStart = cNameLength;
while(buffer[valueStart] == ' ')
++valueStart;
int valueEnd = valueStart;
while(buffer[valueEnd] != '\0' && buffer[valueEnd] != '\r' && buffer[valueEnd] != '\n')
++valueEnd;
int valueLength = valueEnd - valueStart;
if(valueLength > 0) {
value = malloc(valueLength + 1);
value[valueLength] = '\0';
memcpy(value, &buffer[valueStart], valueLength);
}
break;
}
}
mtx_unlock(info->lock);
if(value == NULL && fallback != NULL) {
int length = strlen(fallback) + 1;
value = malloc(length);
memset(value, 0, length);
strcat(value, fallback);
}
return value;
}
sat_config_ptr sat_config_alloc_stream(void) {
sat_config_ptr ctx = malloc(sizeof(sat_config));
memset(ctx, 0, sizeof(sat_config));
ctx->type = SAT_CONFIG_TYPE_STREAM;
ctx->scopeTo = sat_config_stream_scope_to;
ctx->readValue = sat_config_stream_read_value;
sat_config_stream_ptr info = malloc(sizeof(sat_config_stream));
memset(info, 0, sizeof(sat_config_stream));
ctx->info = (void*)info;
info->lock = malloc(sizeof(mtx_t));
return ctx;
}
void sat_config_free_stream(sat_config_ptr ctx) {
if(ctx == NULL || ctx->info == NULL || ctx->type != SAT_CONFIG_TYPE_STREAM) return;
sat_config_stream_ptr info = (sat_config_stream_ptr)ctx->info;
if(info->lock != NULL) {
mtx_destroy(info->lock);
free(info->lock);
}
if(info->ownsStream && info->stream != NULL)
free(info->stream);
free(ctx->info);
free(ctx);
}
int sat_config_stream_open(sat_config_ptr ctx, FILE *stream, bool ownsStream) {
if(ctx == NULL) return -10; // TODO: No.
if(ctx->type != SAT_CONFIG_TYPE_STREAM) return -11;
if(ctx->info == NULL) return -12;
sat_config_stream_ptr info = (sat_config_stream_ptr)ctx->info;
int err = mtx_init(info->lock, mtx_timed);
if(err == thrd_error) return -11;
info->stream = stream;
info->ownsStream = ownsStream;
// check for BOM
uint8_t buffer[3] = {0};
int read = fread(buffer, sizeof(uint8_t), sizeof buffer, stream);
if(buffer[0] != 0xEF || buffer[1] != 0xBB || buffer[2] != 0xBF)
fseek(stream, -read, SEEK_CUR);
info->offset = ftell(stream);
return 0;
}
int sat_config_stream_open_file(sat_config_ptr ctx, char *path) {
if(ctx == NULL) return -10; // TODO: No!
if(ctx->type != SAT_CONFIG_TYPE_STREAM) return -11;
if(ctx->info == NULL) return -12;
FILE *stream = fopen(path, "rb");
if(stream == NULL) return errno;
fseek(stream, 0, SEEK_SET);
return sat_config_stream_open(ctx, stream, true);
}