Pure C config reader
- config.c
/*
* Author, Copyright: Oleg Borodin <onborodin@gmail.com>
*/
#include <regex.h>
#define _WITH_GETLINE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "vector.h"
typedef struct keyvalue {
char* key;
char* value;
} keyvalue_t;
int config_kvmatch(char* str, keyvalue_t** kv) {
size_t nmatch = 4;
regmatch_t pmatch[5];
char* pattern = "^[\t ]*([A-Za-z0-9_\\.]+)[\t ]*[=:]+[\t ]*([A-Za-z0-9_\\.]+)[\t #;]*";
regex_t preg;
int rc;
if ((rc = regcomp(&preg, pattern, REG_EXTENDED)) != 0) {
regfree(&preg);
return -1;
}
if ((rc = regexec(&preg, str, nmatch, pmatch, 0)) != 0) {
regfree(&preg);
return -1;
}
if (pmatch[1].rm_so < 0 || pmatch[2].rm_so < 0) {
regfree(&preg);
return -1;
}
*kv = (keyvalue_t*)malloc(sizeof(keyvalue_t));
if (*kv == NULL) {
regfree(&preg);
return -1;
}
(*kv)->value = NULL;
(*kv)->key = NULL;
size_t ksize = pmatch[1].rm_eo - pmatch[1].rm_so;
(*kv)->key = (char*)malloc(ksize);
memset((void*)(*kv)->key, 0, ksize);
memcpy((*kv)->key, &str[pmatch[1].rm_so], ksize);
size_t vsize = pmatch[2].rm_eo - pmatch[2].rm_so;
(*kv)->value = (char*)malloc(vsize);
memset((*kv)->value, 0, vsize);
memcpy((*kv)->value, &str[pmatch[2].rm_so], vsize);
regfree(&preg);
return 1;
}
vector_t* config_read(char* filename) {
if (filename == NULL) return NULL;
FILE* fp = fopen(filename, "r");
if (fp == NULL) return NULL;
char *line = NULL;
size_t linecap = 0;
ssize_t linelen;
vector_t* v = vector_create();
if (v == NULL) return NULL;
while ((linelen = getline(&line, &linecap, fp)) > 0) {
keyvalue_t* kv = NULL;
if (config_kvmatch(line, &kv) < 0) continue;
vector_add(v, kv);
}
free(line);
fclose(fp);
return v;
}
char* config_getv(vector_t* v, char* key) {
if (key == NULL || v == NULL) return NULL;
for(int i = 0; i < vector_size(v); i++) {
keyvalue_t* kv = vector_get(v, i);
if (kv->key != NULL && kv->value != NULL) {
if (strcmp(key, kv->key) == 0) {
return kv->value;
}
}
}
return NULL;
}
void config_free(vector_t* v) {
if (v == NULL) return;
for(int i = 0; i < vector_size(v); i++) {
keyvalue_t* kv = vector_get(v, i);
if (kv->key != NULL) free(kv->key);
if (kv->value != NULL) free(kv->value);
if (kv != NULL) free(kv);
}
vector_free(v);
}
int main(int argc, char **argv) {
vector_t* confv = config_read("sample.conf");
if (confv == NULL) return 1;
for(int i = 0; i < vector_size(confv); i++) {
keyvalue_t* kv = vector_get(confv, i);
printf("%s=%s;\n", kv->key, kv->value);
}
printf("get some: %s\n", config_getv(confv, "some"));
config_free(confv);
return 0;
}
- vector.h
/*
* Author, Copyright: Oleg Borodin <onborodin@gmail.com>
*/
#ifndef VECTOR_H_QWE
#define VECTOR_H_QWE
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#define VECTOR_INIT_CAPACITY 4
typedef struct vector {
void **items;
int capacity;
int size;
} vector_t;
vector_t* vector_create() {
vector_t* v = malloc(sizeof(vector_t));
if (v == NULL) return NULL;
v->capacity = VECTOR_INIT_CAPACITY;
v->size = 0;
v->items = malloc(sizeof(void*) * v->capacity);
return v;
}
int vector_size(vector_t *v) {
return v->size;
}
int vector_resize(vector_t *v, int capacity) {
void **newitems = realloc(v->items, sizeof(void*) * capacity);
if (newitems != NULL) {
v->items = newitems;
v->capacity = capacity;
return 1;
}
return -1;
}
int vector_add(vector_t *v, void *item) {
if (v->capacity == v->size) {
if (vector_resize(v, v->capacity * 2) < 0) {
return -1;
}
}
v->items[v->size++] = item;
return 1;
}
int vector_set(vector_t *v, int index, void *item) {
if (index >= 0 && index < v->size) {
v->items[index] = item;
return 1;
}
return -1;
}
void* vector_get(vector_t *v, int index) {
if (index >= 0 && index < v->size) {
return v->items[index];
}
return NULL;
}
int vector_delete(vector_t *v, int index) {
if (index < 0 || index >= v->size) {
return -1;
}
v->items[index] = NULL;
for (int i = index; i < v->size - 1; i++) {
v->items[i] = v->items[i + 1];
v->items[i + 1] = NULL;
}
v->size--;
if (v->size > 0 && v->size == v->capacity / 4) {
vector_resize(v, v->capacity / 2);
}
return 1;
}
void vector_free(vector_t *v) {
if (v->items != NULL) free(v->items);
if (v != NULL) free(v);
}
#endif
- sample.conf
# comment
= badvalue;
some = bare
foo = qwerty #comment
rur=krewr;
oldv : uio;
avert = 456; //
avert2 = 789 //
#end
Out
$ ./config
some=bare;
foo=qwerty;
rur=krewr;
oldv=uio;
avert=456;
avert2=789;
get some: bare
$
leak memory