#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); }