User Tools

Site Tools


Pure C config reader

config.c
/*
 * Copyright 2004-2019 Oleg Borodin  <borodin@unix7.org>
 */
 
#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
/*
 * Copyright 2004-2019 Oleg Borodin  <borodin@unix7.org>
 */
 
#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

==57064== LEAK SUMMARY:
==57064==    definitely lost: 0 bytes in 0 blocks
==57064==    indirectly lost: 0 bytes in 0 blocks
==57064==      possibly lost: 0 bytes in 0 blocks
==57064==    still reachable: 1,184 bytes in 2 blocks
==57064==         suppressed: 0 bytes in 0 blocks

First PagePrevious PageBack to overviewNext PageLast Page