#include "CgeConf.h" #include #include #include #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)) == (size_t)-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 == (size_t)-1) return 0; view.data = buffer; parseLine(&view, callback, user); } return 1; }