|
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 |