src/properties.c

changeset 928
d2d42cb1d59e
parent 924
3c90dfc35f06
child 929
192a440b99df
equal deleted inserted replaced
927:71e7e9ba4b97 928:d2d42cb1d59e
90 } 90 }
91 const char *src = prop->text + prop->text_pos; 91 const char *src = prop->text + prop->text_pos;
92 char *dest = prop->buf + prop->buf_size; 92 char *dest = prop->buf + prop->buf_size;
93 memcpy(dest, src, len); 93 memcpy(dest, src, len);
94 prop->buf_size += len; 94 prop->buf_size += len;
95 prop->text_pos += len;
95 return 0; 96 return 0;
96 } 97 }
97 98
98 static int cx_properties_rescue_input(CxProperties *prop) { 99 static int cx_properties_rescue_input(CxProperties *prop) {
99 // someone fucked around with our integers, exit immediately 100 // someone fucked around with our integers, exit immediately
135 prop->buf_capacity = capacity; 136 prop->buf_capacity = capacity;
136 prop->buf_size = 0; 137 prop->buf_size = 0;
137 prop->flags |= CX_PROPERTIES_FLAG_USE_STACK; 138 prop->flags |= CX_PROPERTIES_FLAG_USE_STACK;
138 } 139 }
139 140
140 enum cx_properties_status cxPropertiesNext( 141 CxPropertiesStatus cxPropertiesNext(
141 CxProperties *prop, 142 CxProperties *prop,
142 cxstring *key, 143 cxstring *key,
143 cxstring *value 144 cxstring *value
144 ) { 145 ) {
145 // check if we have a text buffer 146 // check if we have a text buffer
169 prop->text = prop->buf; 170 prop->text = prop->buf;
170 prop->text_size = prop->buf_size; 171 prop->text_size = prop->buf_size;
171 prop->text_pos = 0; 172 prop->text_pos = 0;
172 prop->buf_size = 0; 173 prop->buf_size = 0;
173 174
174 enum cx_properties_status result; 175 CxPropertiesStatus result;
175 result = cxPropertiesNext(prop, key, value); 176 result = cxPropertiesNext(prop, key, value);
176 177
177 // restore original buffer 178 // restore original buffer
178 prop->text = orig_text; 179 prop->text = orig_text;
179 prop->text_size = orig_size; 180 prop->text_size = orig_size;
197 // do not reset the rescue buffer and return the error 198 // do not reset the rescue buffer and return the error
198 return result; 199 return result;
199 } 200 }
200 } else { 201 } else {
201 // still not enough data 202 // still not enough data
203 if (cx_properties_rescue_input(prop)) {
204 return CX_PROPERTIES_BUFFER_ALLOC_FAILED;
205 }
202 return CX_PROPERTIES_INCOMPLETE_DATA; 206 return CX_PROPERTIES_INCOMPLETE_DATA;
203 } 207 }
204 } 208 }
205 209
206 char comment1 = prop->config.comment1; 210 char comment1 = prop->config.comment1;
239 } 243 }
240 } 244 }
241 245
242 if (c != '\n') { 246 if (c != '\n') {
243 // we don't have enough data for a line 247 // we don't have enough data for a line
248 if (cx_properties_rescue_input(prop)) {
249 return CX_PROPERTIES_BUFFER_ALLOC_FAILED;
250 }
244 return CX_PROPERTIES_INCOMPLETE_DATA; 251 return CX_PROPERTIES_INCOMPLETE_DATA;
245 } 252 }
246 253
247 cxstring line = has_comment ? 254 cxstring line = has_comment ?
248 cx_strn(buf, comment_index) : 255 cx_strn(buf, comment_index) :
282 289
283 // when we come to this point, all data must have been read 290 // when we come to this point, all data must have been read
284 assert(prop->text_pos == prop->text_size); 291 assert(prop->text_pos == prop->text_size);
285 return CX_PROPERTIES_NO_DATA; 292 return CX_PROPERTIES_NO_DATA;
286 } 293 }
294
295 static int cx_properties_sink_map(
296 __attribute__((__unused__)) CxProperties *prop,
297 CxPropertiesSink *sink,
298 cxstring key,
299 cxstring value
300 ) {
301 CxMap *map = sink->sink;
302 CxAllocator *alloc = sink->data;
303 cxmutstr v = cx_strdup_a(alloc, value);
304 int r = cx_map_put_cxstr(map, key, v.ptr);
305 if (r != 0) cx_strfree_a(alloc, &v);
306 return r;
307 }
308
309 CxPropertiesSink cxPropertiesMapSink(CxMap *map) {
310 CxPropertiesSink sink;
311 sink.sink = map;
312 sink.data = cxDefaultAllocator;
313 sink.sink_func = cx_properties_sink_map;
314 return sink;
315 }
316
317 static int cx_properties_read_string(
318 CxProperties *prop,
319 CxPropertiesSource *src,
320 cxstring *target
321 ) {
322 if (prop->text == src->src) {
323 // when the input buffer already contains the string
324 // we have nothing more to provide
325 target->length = 0;
326 } else {
327 target->ptr = src->src;
328 target->length = src->data_size;
329 }
330 return 0;
331 }
332
333 static int cx_properties_read_file(
334 __attribute__((__unused__)) CxProperties *prop,
335 CxPropertiesSource *src,
336 cxstring *target
337 ) {
338 target->ptr = src->data_ptr;
339 target->length = fread(src->data_ptr, 1, src->data_size, src->src);
340 return ferror(src->src);
341 }
342
343 static int cx_properties_read_init_file(
344 __attribute__((__unused__)) CxProperties *prop,
345 CxPropertiesSource *src
346 ) {
347 src->data_ptr = malloc(src->data_size);
348 if (src->data_ptr == NULL) return 1;
349 return 0;
350 }
351
352 static void cx_properties_read_clean_file(
353 __attribute__((__unused__)) CxProperties *prop,
354 CxPropertiesSource *src
355 ) {
356 free(src->data_ptr);
357 }
358
359 CxPropertiesSource cxPropertiesStringSource(cxstring str) {
360 CxPropertiesSource src;
361 src.src = (void*) str.ptr;
362 src.data_size = str.length;
363 src.read_func = cx_properties_read_string;
364 src.read_init_func = NULL;
365 src.read_clean_func = NULL;
366 return src;
367 }
368
369 CxPropertiesSource cxPropertiesCstrnSource(const char *str, size_t len) {
370 CxPropertiesSource src;
371 src.src = (void*) str;
372 src.data_size = len;
373 src.read_func = cx_properties_read_string;
374 src.read_init_func = NULL;
375 src.read_clean_func = NULL;
376 return src;
377 }
378
379 CxPropertiesSource cxPropertiesCstrSource(const char *str) {
380 CxPropertiesSource src;
381 src.src = (void*) str;
382 src.data_size = strlen(str);
383 src.read_func = cx_properties_read_string;
384 src.read_init_func = NULL;
385 src.read_clean_func = NULL;
386 return src;
387 }
388
389 CxPropertiesSource cxPropertiesFileSource(FILE *file, size_t chunk_size) {
390 CxPropertiesSource src;
391 src.src = file;
392 src.data_size = chunk_size;
393 src.read_func = cx_properties_read_file;
394 src.read_init_func = cx_properties_read_init_file;
395 src.read_clean_func = cx_properties_read_clean_file;
396 return src;
397 }
398
399 CxPropertiesStatus cxPropertiesLoad(
400 CxProperties *prop,
401 CxPropertiesSink sink,
402 CxPropertiesSource source
403 ) {
404 assert(source.read_func != NULL);
405 assert(sink.sink_func != NULL);
406
407 // initialize reader
408 if (source.read_init_func != NULL) {
409 if (source.read_init_func(prop, &source)) {
410 return CX_PROPERTIES_READ_INIT_FAILED;
411 }
412 }
413
414 // transfer the data from the source to the sink
415 CxPropertiesStatus status;
416 bool found = false;
417 while (true) {
418 // read input
419 cxstring input;
420 if (source.read_func(prop, &source, &input)) {
421 status = CX_PROPERTIES_READ_FAILED;
422 break;
423 }
424
425 // no more data - break
426 if (input.length == 0) {
427 status = found ? CX_PROPERTIES_NO_ERROR : CX_PROPERTIES_NO_DATA;
428 break;
429 }
430
431 // set the input buffer and read the k/v-pairs
432 cxPropertiesInput(prop, input.ptr, input.length);
433
434 CxPropertiesStatus kv_status;
435 do {
436 cxstring key, value;
437 kv_status = cxPropertiesNext(prop, &key, &value);
438 if (kv_status == CX_PROPERTIES_NO_ERROR) {
439 found = true;
440 if (sink.sink_func(prop, &sink, key, value)) {
441 kv_status = CX_PROPERTIES_SINK_FAILED;
442 }
443 }
444 } while (kv_status == CX_PROPERTIES_NO_ERROR);
445
446 if (kv_status > CX_PROPERTIES_OK) {
447 status = kv_status;
448 break;
449 }
450 }
451
452 if (source.read_clean_func != NULL) {
453 source.read_clean_func(prop, &source);
454 }
455
456 return status;
457 }

mercurial