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