ucx/properties.c

changeset 108
d2b1e67b2b48
child 109
75cb6590358b
equal deleted inserted replaced
107:86b19c98b5fd 108:d2b1e67b2b48
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2013 Olaf Wintermann. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "properties.h"
34
35 UcxPropParser *ucx_prop_new() {
36 UcxPropParser *parser = (UcxPropParser*)malloc(
37 sizeof(UcxPropParser));
38 if(!parser) {
39 return NULL;
40 }
41
42 parser->buffer = NULL;
43 parser->buflen = 0;
44 parser->pos = 0;
45 parser->tmp = NULL;
46 parser->tmplen = 0;
47 parser->tmpcap = 0;
48 parser->delimiter = '=';
49 parser->comment1 = '#';
50 parser->comment2 = 0;
51 parser->comment3 = 0;
52
53 return parser;
54 }
55
56 void ucx_prop_free(UcxPropParser *parser) {
57 if(parser->tmp) {
58 free(parser->tmp);
59 }
60 free(parser);
61 }
62
63 void ucx_prop_fill(UcxPropParser *parser, char *buf, size_t len) {
64 parser->buffer = buf;
65 parser->buflen = len;
66 parser->pos = 0;
67 }
68
69 static void parser_tmp_append(UcxPropParser *parser, char *buf, size_t len) {
70 if(parser->tmpcap - parser->tmplen < len) {
71 size_t newcap = parser->tmpcap + len + 64;
72 parser->tmp = (char*)realloc(parser->tmp, newcap);
73 parser->tmpcap = newcap;
74 }
75 memcpy(parser->tmp + parser->tmplen, buf, len);
76 parser->tmplen += len;
77 }
78
79 int ucx_prop_parse(UcxPropParser *parser, sstr_t *name, sstr_t *value) {
80 if(parser->tmplen > 0) {
81 char *buf = parser->buffer + parser->pos;
82 size_t len = parser->buflen - parser->pos;
83 sstr_t str = sstrn(buf, len);
84 sstr_t nl = sstrchr(str, '\n');
85 if(nl.ptr) {
86 size_t newlen = (size_t)(nl.ptr - buf) + 1;
87 parser_tmp_append(parser, buf, newlen);
88 // the tmp buffer contains exactly one line now
89
90 char *orig_buf = parser->buffer;
91 size_t orig_len = parser->buflen;
92
93 parser->buffer = parser->tmp;
94 parser->buflen = parser->tmplen;
95 parser->pos = 0;
96 parser->tmp = NULL;
97 parser->tmpcap = 0;
98 parser->tmplen = 0;
99 // run parse with the tmp buffer as main buffer
100 int ret = ucx_prop_parse(parser, name, value);
101
102 // restore original buffer
103 parser->tmp = parser->buffer;
104 parser->buffer = orig_buf;
105 parser->buflen = orig_len;
106 parser->pos = newlen;
107
108 /*
109 * if ret == 0 the tmp buffer contained just space or comment
110 * we parse again with the original buffer to get a name/value
111 * or a new tmp buffer
112 */
113 return ret ? ret : ucx_prop_parse(parser, name, value);
114 } else {
115 parser_tmp_append(parser, buf, len);
116 return 0;
117 }
118 } else if(parser->tmp) {
119 free(parser->tmp);
120 parser->tmp = NULL;
121 }
122
123 char comment1 = parser->comment1;
124 char comment2 = parser->comment2;
125 char comment3 = parser->comment3;
126 char delimiter = parser->delimiter;
127
128 // get one line and parse it
129 while(1) {
130 if(parser->pos >= parser->buflen) {
131 return 0;
132 }
133 char *buf = parser->buffer + parser->pos;
134 size_t len = parser->buflen - parser->pos;
135
136 /*
137 * First we check if we have at least one line. We also get indices of
138 * delimiter and comment chars
139 */
140 size_t delimiter_index = 0;
141 size_t comment_index = 0;
142 int has_comment = 0;
143
144 size_t i = 0;
145 char c = 0;
146 for(;i<len;i++) {
147 c = buf[i];
148 if(c == comment1 || c == comment2 || c == comment3) {
149 if(comment_index == 0) {
150 comment_index = i;
151 has_comment = 1;
152 }
153 } else if(c == delimiter) {
154 if(delimiter_index == 0 && !has_comment) {
155 delimiter_index = i;
156 }
157 } else if(c == '\n') {
158 break;
159 }
160 }
161
162 if(c != '\n') {
163 // we have not enough data for a line
164 // store remaining bytes in temporary buffer for next round
165 parser->tmpcap = len + 128;
166 parser->tmp = (char*)malloc(parser->tmpcap);
167 parser->tmplen = len;
168 memcpy(parser->tmp, buf, len);
169 return 0;
170 }
171
172 sstr_t line = has_comment ? sstrn(buf, comment_index) : sstrn(buf, i);
173 // check line
174 if(delimiter_index == 0) {
175 line = sstrtrim(line);
176 if(line.length != 0) {
177 // syntax error
178 // TODO
179 }
180 parser->pos += i + 1;
181 continue;
182 }
183
184 sstr_t n = sstrn(buf, delimiter_index);
185 sstr_t v = sstrn(buf + delimiter_index + 1, i - delimiter_index - 1);
186 n = sstrtrim(n);
187 v = sstrtrim(v);
188 if(n.length == 0 || v.length == 0) {
189 // syntax error
190 // TODO
191 parser->pos += i + 1;
192 continue;
193 }
194
195 *name = n;
196 *value = v;
197
198 parser->pos += i + 1;
199 break;
200 }
201
202 return 1;
203 }
204

mercurial