1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/properties.c Tue Oct 17 16:15:41 2017 +0200 1.3 @@ -0,0 +1,264 @@ 1.4 +/* 1.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 1.6 + * 1.7 + * Copyright 2017 Olaf Wintermann. All rights reserved. 1.8 + * 1.9 + * Redistribution and use in source and binary forms, with or without 1.10 + * modification, are permitted provided that the following conditions are met: 1.11 + * 1.12 + * 1. Redistributions of source code must retain the above copyright 1.13 + * notice, this list of conditions and the following disclaimer. 1.14 + * 1.15 + * 2. Redistributions in binary form must reproduce the above copyright 1.16 + * notice, this list of conditions and the following disclaimer in the 1.17 + * documentation and/or other materials provided with the distribution. 1.18 + * 1.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 1.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 1.29 + * POSSIBILITY OF SUCH DAMAGE. 1.30 + */ 1.31 + 1.32 +#include "ucx/properties.h" 1.33 + 1.34 +#include <stdio.h> 1.35 +#include <stdlib.h> 1.36 +#include <string.h> 1.37 + 1.38 +UcxProperties *ucx_properties_new() { 1.39 + UcxProperties *parser = (UcxProperties*)malloc( 1.40 + sizeof(UcxProperties)); 1.41 + if(!parser) { 1.42 + return NULL; 1.43 + } 1.44 + 1.45 + parser->buffer = NULL; 1.46 + parser->buflen = 0; 1.47 + parser->pos = 0; 1.48 + parser->tmp = NULL; 1.49 + parser->tmplen = 0; 1.50 + parser->tmpcap = 0; 1.51 + parser->error = 0; 1.52 + parser->delimiter = '='; 1.53 + parser->comment1 = '#'; 1.54 + parser->comment2 = 0; 1.55 + parser->comment3 = 0; 1.56 + 1.57 + return parser; 1.58 +} 1.59 + 1.60 +void ucx_properties_free(UcxProperties *parser) { 1.61 + if(parser->tmp) { 1.62 + free(parser->tmp); 1.63 + } 1.64 + free(parser); 1.65 +} 1.66 + 1.67 +void ucx_properties_fill(UcxProperties *parser, char *buf, size_t len) { 1.68 + parser->buffer = buf; 1.69 + parser->buflen = len; 1.70 + parser->pos = 0; 1.71 +} 1.72 + 1.73 +static void parser_tmp_append(UcxProperties *parser, char *buf, size_t len) { 1.74 + if(parser->tmpcap - parser->tmplen < len) { 1.75 + size_t newcap = parser->tmpcap + len + 64; 1.76 + parser->tmp = (char*)realloc(parser->tmp, newcap); 1.77 + parser->tmpcap = newcap; 1.78 + } 1.79 + memcpy(parser->tmp + parser->tmplen, buf, len); 1.80 + parser->tmplen += len; 1.81 +} 1.82 + 1.83 +int ucx_properties_next(UcxProperties *parser, sstr_t *name, sstr_t *value) { 1.84 + if(parser->tmplen > 0) { 1.85 + char *buf = parser->buffer + parser->pos; 1.86 + size_t len = parser->buflen - parser->pos; 1.87 + sstr_t str = sstrn(buf, len); 1.88 + sstr_t nl = sstrchr(str, '\n'); 1.89 + if(nl.ptr) { 1.90 + size_t newlen = (size_t)(nl.ptr - buf) + 1; 1.91 + parser_tmp_append(parser, buf, newlen); 1.92 + // the tmp buffer contains exactly one line now 1.93 + 1.94 + char *orig_buf = parser->buffer; 1.95 + size_t orig_len = parser->buflen; 1.96 + 1.97 + parser->buffer = parser->tmp; 1.98 + parser->buflen = parser->tmplen; 1.99 + parser->pos = 0; 1.100 + parser->tmp = NULL; 1.101 + parser->tmpcap = 0; 1.102 + parser->tmplen = 0; 1.103 + // run ucx_properties_next with the tmp buffer as main buffer 1.104 + int ret = ucx_properties_next(parser, name, value); 1.105 + 1.106 + // restore original buffer 1.107 + parser->tmp = parser->buffer; 1.108 + parser->buffer = orig_buf; 1.109 + parser->buflen = orig_len; 1.110 + parser->pos = newlen; 1.111 + 1.112 + /* 1.113 + * if ret == 0 the tmp buffer contained just space or a comment 1.114 + * we parse again with the original buffer to get a name/value 1.115 + * or a new tmp buffer 1.116 + */ 1.117 + return ret ? ret : ucx_properties_next(parser, name, value); 1.118 + } else { 1.119 + parser_tmp_append(parser, buf, len); 1.120 + return 0; 1.121 + } 1.122 + } else if(parser->tmp) { 1.123 + free(parser->tmp); 1.124 + parser->tmp = NULL; 1.125 + } 1.126 + 1.127 + char comment1 = parser->comment1; 1.128 + char comment2 = parser->comment2; 1.129 + char comment3 = parser->comment3; 1.130 + char delimiter = parser->delimiter; 1.131 + 1.132 + // get one line and parse it 1.133 + while(parser->pos < parser->buflen) { 1.134 + char *buf = parser->buffer + parser->pos; 1.135 + size_t len = parser->buflen - parser->pos; 1.136 + 1.137 + /* 1.138 + * First we check if we have at least one line. We also get indices of 1.139 + * delimiter and comment chars 1.140 + */ 1.141 + size_t delimiter_index = 0; 1.142 + size_t comment_index = 0; 1.143 + int has_comment = 0; 1.144 + 1.145 + size_t i = 0; 1.146 + char c = 0; 1.147 + for(;i<len;i++) { 1.148 + c = buf[i]; 1.149 + if(c == comment1 || c == comment2 || c == comment3) { 1.150 + if(comment_index == 0) { 1.151 + comment_index = i; 1.152 + has_comment = 1; 1.153 + } 1.154 + } else if(c == delimiter) { 1.155 + if(delimiter_index == 0 && !has_comment) { 1.156 + delimiter_index = i; 1.157 + } 1.158 + } else if(c == '\n') { 1.159 + break; 1.160 + } 1.161 + } 1.162 + 1.163 + if(c != '\n') { 1.164 + // we don't have enough data for a line 1.165 + // store remaining bytes in temporary buffer for next round 1.166 + parser->tmpcap = len + 128; 1.167 + parser->tmp = (char*)malloc(parser->tmpcap); 1.168 + parser->tmplen = len; 1.169 + memcpy(parser->tmp, buf, len); 1.170 + return 0; 1.171 + } 1.172 + 1.173 + sstr_t line = has_comment ? sstrn(buf, comment_index) : sstrn(buf, i); 1.174 + // check line 1.175 + if(delimiter_index == 0) { 1.176 + line = sstrtrim(line); 1.177 + if(line.length != 0) { 1.178 + parser->error = 1; 1.179 + } 1.180 + } else { 1.181 + sstr_t n = sstrn(buf, delimiter_index); 1.182 + sstr_t v = sstrn( 1.183 + buf + delimiter_index + 1, 1.184 + line.length - delimiter_index - 1); 1.185 + n = sstrtrim(n); 1.186 + v = sstrtrim(v); 1.187 + if(n.length != 0 || v.length != 0) { 1.188 + *name = n; 1.189 + *value = v; 1.190 + parser->pos += i + 1; 1.191 + return 1; 1.192 + } else { 1.193 + parser->error = 1; 1.194 + } 1.195 + } 1.196 + 1.197 + parser->pos += i + 1; 1.198 + } 1.199 + 1.200 + return 0; 1.201 +} 1.202 + 1.203 +int ucx_properties2map(UcxProperties *parser, UcxMap *map) { 1.204 + sstr_t name; 1.205 + sstr_t value; 1.206 + while(ucx_properties_next(parser, &name, &value)) { 1.207 + value = sstrdup_a(map->allocator, value); 1.208 + if(!value.ptr) { 1.209 + return 1; 1.210 + } 1.211 + if(ucx_map_sstr_put(map, name, value.ptr)) { 1.212 + alfree(map->allocator, value.ptr); 1.213 + return 1; 1.214 + } 1.215 + } 1.216 + if (parser->error) { 1.217 + return parser->error; 1.218 + } else { 1.219 + return 0; 1.220 + } 1.221 +} 1.222 + 1.223 +// buffer size is documented - change doc, when you change bufsize! 1.224 +#define UCX_PROPLOAD_BUFSIZE 1024 1.225 +int ucx_properties_load(UcxMap *map, FILE *file) { 1.226 + UcxProperties *parser = ucx_properties_new(); 1.227 + if(!(parser && map && file)) { 1.228 + return 1; 1.229 + } 1.230 + 1.231 + int error = 0; 1.232 + size_t r; 1.233 + char buf[UCX_PROPLOAD_BUFSIZE]; 1.234 + while((r = fread(buf, 1, UCX_PROPLOAD_BUFSIZE, file)) != 0) { 1.235 + ucx_properties_fill(parser, buf, r); 1.236 + error = ucx_properties2map(parser, map); 1.237 + if (error) { 1.238 + break; 1.239 + } 1.240 + } 1.241 + ucx_properties_free(parser); 1.242 + return error; 1.243 +} 1.244 + 1.245 +int ucx_properties_store(UcxMap *map, FILE *file) { 1.246 + UcxMapIterator iter = ucx_map_iterator(map); 1.247 + void *v; 1.248 + sstr_t value; 1.249 + size_t written; 1.250 + 1.251 + UCX_MAP_FOREACH(k, v, iter) { 1.252 + value = sstr((char*)v); 1.253 + 1.254 + written = 0; 1.255 + written += fwrite(k.data, 1, k.len, file); 1.256 + written += fwrite(" = ", 1, 3, file); 1.257 + written += fwrite(value.ptr, 1, value.length, file); 1.258 + written += fwrite("\n", 1, 1, file); 1.259 + 1.260 + if (written != k.len + value.length + 4) { 1.261 + return 1; 1.262 + } 1.263 + } 1.264 + 1.265 + return 0; 1.266 +} 1.267 +