189 lines
4.1 KiB
C
189 lines
4.1 KiB
C
#include "CgeConf.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
#define MAX_LINE 4096
|
|
|
|
typedef struct StrView {
|
|
char *data;
|
|
size_t size;
|
|
} StrView;
|
|
|
|
typedef struct MemCtx {
|
|
const char *buffer;
|
|
size_t size;
|
|
size_t pos;
|
|
} MemCtx;
|
|
|
|
static int memRead(void *ctx, void *buffer, size_t size, size_t *actual) {
|
|
MemCtx *mem = (MemCtx *)ctx;
|
|
size_t remaining = mem->size - mem->pos;
|
|
|
|
if (size > remaining)
|
|
size = remaining;
|
|
|
|
memcpy(buffer, mem->buffer + mem->pos, size);
|
|
mem->pos += size;
|
|
*actual = size;
|
|
return 1;
|
|
}
|
|
|
|
static int fileRead(void *ctx, void *buffer, size_t size, size_t *actual) {
|
|
*actual = fread(buffer, 1, size, (FILE *)ctx);
|
|
return 1;
|
|
}
|
|
|
|
static void trimLeft(StrView *view) {
|
|
for (; view->size && isspace(*view->data); ++view->data, --view->size);
|
|
}
|
|
|
|
static void trimRight(StrView *view) {
|
|
char *last = view->data + view->size;
|
|
for (; last > view->data && isspace(*(last - 1)); last--, view->size--);
|
|
}
|
|
|
|
static void trim(StrView *view) {
|
|
trimLeft(view);
|
|
trimRight(view);
|
|
}
|
|
|
|
static size_t firstIndex(StrView *view, char symbol) {
|
|
char *current, *end;
|
|
current = view->data;
|
|
end = view->data + view->size;
|
|
|
|
for (; current < end; ++current) {
|
|
if (*current == symbol)
|
|
return current - view->data;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int split(StrView *view, StrView *prefix, char delim) {
|
|
size_t position;
|
|
|
|
if ((position = firstIndex(view, delim)) == -1)
|
|
return 0;
|
|
|
|
prefix->data = view->data;
|
|
prefix->size = position;
|
|
view->data += position;
|
|
view->size -= position;
|
|
return 1;
|
|
}
|
|
|
|
static void parseLine(StrView *view, CgeConfCb callback, void *user) {
|
|
StrView key;
|
|
|
|
trim(view);
|
|
|
|
if (!view->size || *view->data == '#' || *view->data == ';')
|
|
return;
|
|
|
|
if (*view->data == '[' && *(view->data + view->size - 1) == ']') {
|
|
view->size -= 2;
|
|
view->data += 1;
|
|
trim(view);
|
|
|
|
view->data[view->size] = 0;
|
|
callback(CGE_CONF_SECTION, NULL, view->data, user);
|
|
} else if (split(view, &key, '=')) {
|
|
trimRight(&key);
|
|
view->data++, view->size--;
|
|
trimLeft(view);
|
|
|
|
if (view->size > 1 && *view->data == '"' &&
|
|
*(view->data + view->size - 1) == '"') {
|
|
view->size -= 2;
|
|
view->data += 1;
|
|
}
|
|
|
|
key.data[key.size] = 0;
|
|
view->data[view->size] = 0;
|
|
callback(CGE_CONF_KEYVALUE, key.data, view->data, user);
|
|
}
|
|
}
|
|
|
|
static int readSymbol(CgeConfIO *io) {
|
|
unsigned char symbol;
|
|
size_t actual;
|
|
|
|
if (!io->read(io->ctx, &symbol, 1, &actual) || !actual)
|
|
return -1;
|
|
|
|
return (int)symbol;
|
|
}
|
|
|
|
static size_t readLine(CgeConfIO *io, char *buffer, size_t size) {
|
|
int symbol;
|
|
size_t counter = 0;
|
|
|
|
while ((symbol = readSymbol(io)) != -1) {
|
|
if (counter && symbol == '\n')
|
|
break;
|
|
else if (symbol == '\n')
|
|
continue;
|
|
|
|
if (symbol == '\r')
|
|
continue;
|
|
|
|
if (counter >= size - 1)
|
|
return -1;
|
|
|
|
buffer[counter++] = symbol;
|
|
}
|
|
|
|
buffer[counter] = 0;
|
|
return counter;
|
|
}
|
|
|
|
int CgeConfFromString(const char *str, CgeConfCb callback, void *user) {
|
|
return CgeConfFromMemory(str, strlen(str), callback, user);
|
|
}
|
|
|
|
int CgeConfFromMemory(const char *buffer, size_t size, CgeConfCb callback,
|
|
void *user) {
|
|
CgeConfIO io;
|
|
MemCtx mem;
|
|
|
|
mem.buffer = buffer;
|
|
mem.size = size;
|
|
mem.pos = 0;
|
|
|
|
io.read = memRead;
|
|
io.ctx = &mem;
|
|
|
|
return CgeConfFromCb(&io, callback, user);
|
|
}
|
|
|
|
int CgeConfFromFile(const char *path, CgeConfCb callback, void *user) {
|
|
CgeConfIO io;
|
|
FILE *file;
|
|
int ret;
|
|
|
|
file = fopen(path, "rb");
|
|
if (!file)
|
|
return 0;
|
|
|
|
io.read = fileRead;
|
|
io.ctx = file;
|
|
|
|
ret = CgeConfFromCb(&io, callback, user);
|
|
fclose(file);
|
|
return ret;
|
|
}
|
|
|
|
int CgeConfFromCb(CgeConfIO *io, CgeConfCb callback, void *user) {
|
|
char buffer[MAX_LINE];
|
|
StrView view;
|
|
|
|
while ((view.size = readLine(io, buffer, MAX_LINE))) {
|
|
if (view.size == -1)
|
|
return 0;
|
|
view.data = buffer;
|
|
parseLine(&view, callback, user);
|
|
}
|
|
return 1;
|
|
}
|