Files
CgeConf/Query.c
T
blankhex bb5e4eeaa9
CI / build-and-analyze (push) Failing after 43s
Initial commit
2026-09-22 19:00:03 +03:00

259 lines
6.4 KiB
C

#include "CgeConfQuery.h"
#include <stdlib.h>
#include <string.h>
#define INIT_EXP 4
#define INIT_CAPACITY ((size_t)1 << INIT_EXP)
#define MAX_SECTION 4096
typedef struct {
char *section;
char *key;
char *value;
} Entry;
struct CgeConfQuery {
Entry *entryData;
size_t size;
size_t capacity;
Entry **slotData;
char currentSection[MAX_SECTION];
int exp;
};
static char *stringDup(const char *str) {
size_t length;
char *dest;
length = strlen(str);
if ((dest = malloc(length + 1)))
memcpy(dest, str, length + 1);
return dest;
}
static size_t hashKey(const char *section, const char *key) {
size_t h = 5381;
const char *p;
int c;
for (p = section; (c = *p); ++p)
h = ((h << 5) + h) + (unsigned char)c;
h = ((h << 5) + h);
for (p = key; (c = *p); ++p)
h = ((h << 5) + h) + (unsigned char)c;
return h;
}
static size_t lookup(size_t hash, int exp, size_t index) {
size_t mask = (1 << exp) - 1;
size_t step = (hash >> (sizeof(hash) * 8 - exp)) | 1;
return (index + step) & mask;
}
static int reserveSpace(CgeConfQuery *query, size_t need) {
CgeConfQuery tmp;
size_t i, hash, index;
if (need <= (query->capacity - (query->capacity >> 2)))
return 1;
tmp.exp = query->exp ? query->exp + 1 : INIT_EXP;
tmp.capacity = query->capacity ? query->capacity * 2 : INIT_CAPACITY;
tmp.size = 0;
tmp.entryData = malloc(tmp.capacity * sizeof(*tmp.entryData));
tmp.slotData = malloc(tmp.capacity * sizeof(*tmp.slotData));
if (!tmp.entryData || !tmp.slotData) {
free(tmp.entryData);
free(tmp.slotData);
return 0;
}
memset(tmp.slotData, 0, sizeof(*tmp.slotData) * tmp.capacity);
for (i = 0; i < query->size; ++i) {
Entry *entry = &query->entryData[i];
hash = hashKey(entry->section, entry->key);
index = lookup(hash, tmp.exp, 0);
while (tmp.slotData[index] != NULL)
index = lookup(hash, tmp.exp, index);
tmp.entryData[tmp.size] = *entry;
tmp.slotData[index] = tmp.entryData + tmp.size++;
}
free(query->entryData);
free(query->slotData);
query->entryData = tmp.entryData;
query->slotData = tmp.slotData;
query->capacity = tmp.capacity;
query->exp = tmp.exp;
return 1;
}
static int insert(CgeConfQuery *query, const char *section, const char *key,
const char *value) {
size_t hash, index;
char *newValue;
Entry *entry;
if (!reserveSpace(query, query->size + 1))
return 0;
hash = hashKey(section, key);
index = lookup(hash, query->exp, 0);
while ((entry = query->slotData[index])) {
if (strcmp(entry->section, section) == 0 &&
strcmp(entry->key, key) == 0) {
newValue = stringDup(value);
if (!newValue)
return 0;
free(entry->value);
entry->value = newValue;
return 1;
}
index = lookup(hash, query->exp, index);
}
entry = &query->entryData[query->size];
entry->section = stringDup(section);
entry->key = stringDup(key);
entry->value = stringDup(value);
if (!entry->section || !entry->key || !entry->value) {
free(entry->section);
free(entry->key);
free(entry->value);
return 0;
}
query->size++;
query->slotData[index] = entry;
return 1;
}
static void populateCb(int type, const char *key, const char *value,
void *user) {
CgeConfQuery *query = (CgeConfQuery *)user;
size_t len;
if (type == CGE_CONF_SECTION) {
len = strlen(value);
if (len >= sizeof(query->currentSection))
len = sizeof(query->currentSection) - 1;
memcpy(query->currentSection, value, len);
query->currentSection[len] = 0;
} else if (type == CGE_CONF_KEYVALUE) {
insert(query, query->currentSection, key, value);
}
}
static CgeConfQuery *queryNew(void) {
CgeConfQuery *query;
query = (CgeConfQuery *)malloc(sizeof(CgeConfQuery));
if (!query)
return NULL;
memset(query, 0, sizeof(*query));
return query;
}
CgeConfQuery *CgeConfQueryFromCb(CgeConfIO *io) {
CgeConfQuery *query;
query = queryNew();
if (!query)
return NULL;
if (!CgeConfFromCb(io, populateCb, query)) {
CgeConfQueryFree(query);
return NULL;
}
return query;
}
CgeConfQuery *CgeConfQueryFromFile(const char *file) {
CgeConfQuery *query;
query = queryNew();
if (!query)
return NULL;
if (!CgeConfFromFile(file, populateCb, query)) {
CgeConfQueryFree(query);
return NULL;
}
return query;
}
CgeConfQuery *CgeConfQueryFromMemory(const char *buffer, size_t size) {
CgeConfQuery *query;
query = queryNew();
if (!query)
return NULL;
if (!CgeConfFromMemory(buffer, size, populateCb, query)) {
CgeConfQueryFree(query);
return NULL;
}
return query;
}
CgeConfQuery *CgeConfQueryFromString(const char *str) {
return CgeConfQueryFromMemory(str, strlen(str));
}
const char *CgeConfQueryGet(CgeConfQuery *query, const char *section,
const char *key, const char *defaultValue) {
size_t hash, index, i;
Entry *entry;
if (!query || !key)
return defaultValue;
if (!section)
section = "";
hash = hashKey(section, key);
index = lookup(hash, query->exp, 0);
for (i = 0; i < query->capacity; ++i) {
entry = query->slotData[index];
if (!entry)
break;
if (strcmp(entry->section, section) == 0 &&
strcmp(entry->key, key) == 0)
return entry->value;
index = lookup(hash, query->exp, index);
}
return defaultValue;
}
void CgeConfQueryFree(CgeConfQuery *query) {
size_t i;
if (!query)
return;
for (i = 0; i < query->size; ++i) {
free(query->entryData[i].section);
free(query->entryData[i].key);
free(query->entryData[i].value);
}
free(query->entryData);
free(query->slotData);
free(query);
}
void CgeConfQueryIter(CgeConfQuery *query, CgeConfQueryIterCb iter,
void *user) {
Entry *entry, *end;
entry = query->entryData;
end = query->entryData + query->size;
for (; entry != end; ++entry)
iter(entry->section, entry->key, entry->value, user);
}