#include "ucx/properties.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
UcxProperties *ucx_properties_new() {
UcxProperties *parser = (UcxProperties*)malloc(
sizeof(UcxProperties));
if(!parser) {
return NULL;
}
parser->buffer =
NULL;
parser->buflen =
0;
parser->pos =
0;
parser->tmp =
NULL;
parser->tmplen =
0;
parser->tmpcap =
0;
parser->error =
0;
parser->delimiter =
'=';
parser->comment1 =
'#';
parser->comment2 =
0;
parser->comment3 =
0;
return parser;
}
void ucx_properties_free(UcxProperties *parser) {
if(parser->tmp) {
free(parser->tmp);
}
free(parser);
}
void ucx_properties_fill(UcxProperties *parser,
char *buf,
size_t len) {
parser->buffer = buf;
parser->buflen = len;
parser->pos =
0;
}
static void parser_tmp_append(UcxProperties *parser,
char *buf,
size_t len) {
if(parser->tmpcap - parser->tmplen < len) {
size_t newcap = parser->tmpcap + len +
64;
parser->tmp = (
char*)realloc(parser->tmp, newcap);
parser->tmpcap = newcap;
}
memcpy(parser->tmp + parser->tmplen, buf, len);
parser->tmplen += len;
}
int ucx_properties_next(UcxProperties *parser,
sstr_t *name,
sstr_t *value) {
if(parser->tmplen >
0) {
char *buf = parser->buffer + parser->pos;
size_t len = parser->buflen - parser->pos;
sstr_t str = sstrn(buf, len);
sstr_t nl = sstrchr(str,
'\n');
if(nl.ptr) {
size_t newlen = (
size_t)(nl.ptr - buf) +
1;
parser_tmp_append(parser, buf, newlen);
char *orig_buf = parser->buffer;
size_t orig_len = parser->buflen;
parser->buffer = parser->tmp;
parser->buflen = parser->tmplen;
parser->pos =
0;
parser->tmp =
NULL;
parser->tmpcap =
0;
parser->tmplen =
0;
int ret = ucx_properties_next(parser, name, value);
parser->tmp = parser->buffer;
parser->buffer = orig_buf;
parser->buflen = orig_len;
parser->pos = newlen;
return ret ? ret : ucx_properties_next(parser, name, value);
}
else {
parser_tmp_append(parser, buf, len);
return 0;
}
}
else if(parser->tmp) {
free(parser->tmp);
parser->tmp =
NULL;
}
char comment1 = parser->comment1;
char comment2 = parser->comment2;
char comment3 = parser->comment3;
char delimiter = parser->delimiter;
while(parser->pos < parser->buflen) {
char *buf = parser->buffer + parser->pos;
size_t len = parser->buflen - parser->pos;
size_t delimiter_index =
0;
size_t comment_index =
0;
int has_comment =
0;
size_t i =
0;
char c =
0;
for(;i<len;i++) {
c = buf[i];
if(c == comment1 || c == comment2 || c == comment3) {
if(comment_index ==
0) {
comment_index = i;
has_comment =
1;
}
}
else if(c == delimiter) {
if(delimiter_index ==
0 && !has_comment) {
delimiter_index = i;
}
}
else if(c ==
'\n') {
break;
}
}
if(c !=
'\n') {
parser->tmpcap = len +
128;
parser->tmp = (
char*)malloc(parser->tmpcap);
parser->tmplen = len;
memcpy(parser->tmp, buf, len);
return 0;
}
sstr_t line = has_comment ? sstrn(buf, comment_index) : sstrn(buf, i);
if(delimiter_index ==
0) {
line = sstrtrim(line);
if(line.length !=
0) {
parser->error =
1;
}
}
else {
sstr_t n = sstrn(buf, delimiter_index);
sstr_t v = sstrn(
buf + delimiter_index +
1,
line.length - delimiter_index -
1);
n = sstrtrim(n);
v = sstrtrim(v);
if(n.length !=
0 || v.length !=
0) {
*name = n;
*value = v;
parser->pos += i +
1;
return 1;
}
else {
parser->error =
1;
}
}
parser->pos += i +
1;
}
return 0;
}
int ucx_properties2map(UcxProperties *parser, UcxMap *map) {
sstr_t name;
sstr_t value;
while(ucx_properties_next(parser, &name, &value)) {
value = sstrdup_a(map->allocator, value);
if(!value.ptr) {
return 1;
}
if(ucx_map_sstr_put(map, name, value.ptr)) {
alfree(map->allocator, value.ptr);
return 1;
}
}
if (parser->error) {
return parser->error;
}
else {
return 0;
}
}
#define UCX_PROPLOAD_BUFSIZE 1024
int ucx_properties_load(UcxMap *map,
FILE *file) {
UcxProperties *parser = ucx_properties_new();
if(!(parser && map && file)) {
return 1;
}
int error =
0;
size_t r;
char buf[
UCX_PROPLOAD_BUFSIZE];
while((r = fread(buf,
1,
UCX_PROPLOAD_BUFSIZE, file)) !=
0) {
ucx_properties_fill(parser, buf, r);
error = ucx_properties2map(parser, map);
if (error) {
break;
}
}
ucx_properties_free(parser);
return error;
}
int ucx_properties_store(UcxMap *map,
FILE *file) {
UcxMapIterator iter = ucx_map_iterator(map);
void *v;
sstr_t value;
size_t written;
UCX_MAP_FOREACH(k, v, iter) {
value = sstr((
char*)v);
written =
0;
written += fwrite(k.data,
1, k.len, file);
written += fwrite(
" = ",
1,
3, file);
written += fwrite(value.ptr,
1, value.length, file);
written += fwrite(
"\n",
1,
1, file);
if (written != k.len + value.length +
4) {
return 1;
}
}
return 0;
}