Have to add is_combining functions to detect combining for the purpose of FSS processing.
Skip past initial place holders in the skip functions.
The initial combining returns `F_complete_not_utf_start` only for combining at the start.
This should be then handled as a combining.
Begin adding the unit tests.
These should fail because the functionality that they are testing is not implemented.
What needs to be done next is to have all FSS processing code look past the special characters (except new lines).
Check for combining characters.
#define _di_f_fss_simple_packetss_delete_callback_
#define _di_f_fss_simple_packetss_destroy_callback_
#define _di_f_fss_simple_packetss_t_
+#define _di_f_fss_skip_past_combining_
#define _di_f_fss_skip_past_delimit_
#define _di_f_fss_skip_past_space_
#define _di_f_fss_state_flag_e_
#define _di_f_fss_simple_packetss_delete_callback_
#define _di_f_fss_simple_packetss_destroy_callback_
#define _di_f_fss_simple_packetss_t_
+//#define _di_f_fss_skip_past_combining_
//#define _di_f_fss_skip_past_delimit_
//#define _di_f_fss_skip_past_space_
//#define _di_f_fss_state_flag_e_
#define _di_f_fss_simple_packetss_delete_callback_
#define _di_f_fss_simple_packetss_destroy_callback_
#define _di_f_fss_simple_packetss_t_
+#define _di_f_fss_skip_past_combining_
#define _di_f_fss_skip_past_delimit_
#define _di_f_fss_skip_past_space_
#define _di_f_fss_state_flag_e_
#define _di_f_fss_simple_packetss_delete_callback_
#define _di_f_fss_simple_packetss_destroy_callback_
#define _di_f_fss_simple_packetss_t_
+//#define _di_f_fss_skip_past_combining_
//#define _di_f_fss_skip_past_delimit_
//#define _di_f_fss_skip_past_space_
//#define _di_f_fss_state_flag_e_
#define _di_f_fss_simple_packetss_delete_callback_
#define _di_f_fss_simple_packetss_destroy_callback_
#define _di_f_fss_simple_packetss_t_
+//#define _di_f_fss_skip_past_combining_
//#define _di_f_fss_skip_past_delimit_
//#define _di_f_fss_skip_past_space_
//#define _di_f_fss_state_flag_e_
#define _di_f_fss_simple_packetss_delete_callback_
#define _di_f_fss_simple_packetss_destroy_callback_
#define _di_f_fss_simple_packetss_t_
+//#define _di_f_fss_skip_past_combining_
//#define _di_f_fss_skip_past_delimit_
//#define _di_f_fss_skip_past_space_
//#define _di_f_fss_state_flag_e_
#define _di_f_fss_simple_packetss_delete_callback_
#define _di_f_fss_simple_packetss_destroy_callback_
#define _di_f_fss_simple_packetss_t_
+//#define _di_f_fss_skip_past_combining_
//#define _di_f_fss_skip_past_delimit_
//#define _di_f_fss_skip_past_space_
//#define _di_f_fss_state_flag_e_
#define _di_f_fss_simple_packetss_delete_callback_
#define _di_f_fss_simple_packetss_destroy_callback_
#define _di_f_fss_simple_packetss_t_
+//#define _di_f_fss_skip_past_combining_
//#define _di_f_fss_skip_past_delimit_
//#define _di_f_fss_skip_past_space_
//#define _di_f_fss_state_flag_e_
#define _di_f_fss_simple_packetss_delete_callback_
#define _di_f_fss_simple_packetss_destroy_callback_
#define _di_f_fss_simple_packetss_t_
+//#define _di_f_fss_skip_past_combining_
//#define _di_f_fss_skip_past_delimit_
//#define _di_f_fss_skip_past_space_
//#define _di_f_fss_state_flag_e_
#define _di_f_fss_simple_packetss_delete_callback_
#define _di_f_fss_simple_packetss_destroy_callback_
#define _di_f_fss_simple_packetss_t_
+//#define _di_f_fss_skip_past_combining_
//#define _di_f_fss_skip_past_delimit_
//#define _di_f_fss_skip_past_space_
//#define _di_f_fss_state_flag_e_
#define _di_f_fss_simple_packetss_delete_callback_
#define _di_f_fss_simple_packetss_destroy_callback_
#define _di_f_fss_simple_packetss_t_
+//#define _di_f_fss_skip_past_combining_
//#define _di_f_fss_skip_past_delimit_
//#define _di_f_fss_skip_past_space_
//#define _di_f_fss_state_flag_e_
#define _di_f_fss_simple_packetss_delete_callback_
#define _di_f_fss_simple_packetss_destroy_callback_
#define _di_f_fss_simple_packetss_t_
+//#define _di_f_fss_skip_past_combining_
//#define _di_f_fss_skip_past_delimit_
//#define _di_f_fss_skip_past_space_
//#define _di_f_fss_state_flag_e_
#define _di_f_fss_simple_packetss_delete_callback_
#define _di_f_fss_simple_packetss_destroy_callback_
#define _di_f_fss_simple_packetss_t_
+//#define _di_f_fss_skip_past_combining_
//#define _di_f_fss_skip_past_delimit_
//#define _di_f_fss_skip_past_space_
//#define _di_f_fss_state_flag_e_
#define _di_f_fss_simple_packetss_delete_callback_
#define _di_f_fss_simple_packetss_destroy_callback_
#define _di_f_fss_simple_packetss_t_
+//#define _di_f_fss_skip_past_combining_
//#define _di_f_fss_skip_past_delimit_
//#define _di_f_fss_skip_past_space_
//#define _di_f_fss_state_flag_e_
#define _di_f_fss_simple_packetss_delete_callback_
#define _di_f_fss_simple_packetss_destroy_callback_
#define _di_f_fss_simple_packetss_t_
+//#define _di_f_fss_skip_past_combining_
//#define _di_f_fss_skip_past_delimit_
//#define _di_f_fss_skip_past_space_
//#define _di_f_fss_state_flag_e_
#define _di_f_fss_simple_packetss_delete_callback_
#define _di_f_fss_simple_packetss_destroy_callback_
#define _di_f_fss_simple_packetss_t_
+//#define _di_f_fss_skip_past_combining_
//#define _di_f_fss_skip_past_delimit_
//#define _di_f_fss_skip_past_space_
//#define _di_f_fss_state_flag_e_
#define _di_f_fss_simple_packetss_delete_callback_
#define _di_f_fss_simple_packetss_destroy_callback_
#define _di_f_fss_simple_packetss_t_
+//#define _di_f_fss_skip_past_combining_
//#define _di_f_fss_skip_past_delimit_
//#define _di_f_fss_skip_past_space_
//#define _di_f_fss_state_flag_e_
#define _di_f_fss_simple_packetss_delete_callback_
#define _di_f_fss_simple_packetss_destroy_callback_
#define _di_f_fss_simple_packetss_t_
+#define _di_f_fss_skip_past_combining_
#define _di_f_fss_skip_past_delimit_
#define _di_f_fss_skip_past_space_
#define _di_f_fss_state_flag_e_
}
#endif // _di_f_fss_seek_to_eol_
+#ifndef _di_f_fss_skip_past_combining_
+ void f_fss_skip_past_combining(const f_string_static_t buffer, f_range_t * const range, f_state_t * const state) {
+ #ifndef _di_level_0_parameter_checking_
+ if (!state) return;
+
+ if (!range) {
+ state->status = F_status_set_error(F_parameter);
+
+ return;
+ }
+ #endif // _di_level_0_parameter_checking_
+
+ if (!buffer.used || range->start > range->stop || range->start >= buffer.used) {
+ state->status = F_data_not;
+
+ return;
+ }
+
+ // Skip past initial place holders.
+ for (;; ++range->start) {
+
+ if (range->start >= buffer.used) {
+ state->status = F_okay_eos;
+
+ return;
+ }
+
+ if (range->start > range->stop) {
+ state->status = F_okay_stop;
+
+ return;
+ }
+
+ if (buffer.string[range->start] != f_fss_placeholder_s.string[0]) break;
+ } // for
+
+ uint8_t width = 0;
+ f_number_unsigned_t width_max = (range->stop - range->start) + 1;
+
+ if (width_max > buffer.used - range->start) {
+ width_max = buffer.used - range->start;
+ }
+
+ // Check that the first character is not a combining character.
+ state->status = f_utf_is_combining(buffer.string + range->start, width_max);
+
+ f_fss_fail_utf_to_false(state);
+ if (F_status_is_error(state->status)) return;
+
+ if (state->status == F_true) {
+ state->status = F_is_not;
+
+ return;
+ }
+
+ for (;;) {
+
+ width = macro_f_utf_byte_width(buffer.string[range->start]);
+
+ if (width > 1) {
+ if (range->start + width >= buffer.used) {
+ state->status = F_status_set_error(F_complete_not_utf_eos);
+
+ f_fss_fail_utf(state);
+
+ return;
+ }
+
+ if (range->start + width > range->stop) {
+ state->status = F_status_set_error(F_complete_not_utf_stop);
+
+ f_fss_fail_utf(state);
+
+ return;
+ }
+ }
+
+ range->start += width;
+
+ if (range->start >= buffer.used) {
+ state->status = F_okay_eos;
+
+ return;
+ }
+
+ if (range->start > range->stop) {
+ state->status = F_okay_stop;
+
+ return;
+ }
+
+ width_max = (range->stop - range->start) + 1;
+
+ if (width_max > buffer.used - range->start) {
+ width_max = buffer.used - range->start;
+ }
+
+ if (buffer.string[range->start] == f_fss_eol_s.string[0]) {
+ state->status = F_okay_eol;
+
+ return;
+ }
+
+ if (buffer.string[range->start] == f_fss_placeholder_s.string[0]) {
+ ++range->start;
+
+ continue;
+ }
+
+ state->status = f_utf_is_combining(buffer.string + range->start, width_max);
+
+ f_fss_fail_utf_to_false(state);
+
+ if (state->status == F_false) break;
+ if (F_status_is_error(state->status)) return;
+ } // for
+
+ state->status = F_okay;
+ }
+#endif // _di_f_fss_skip_past_combining_
+
#ifndef _di_f_fss_skip_past_delimit_
void f_fss_skip_past_delimit(const f_string_static_t buffer, f_range_t * const range, f_state_t * const state) {
#ifndef _di_level_0_parameter_checking_
return;
}
+ // Skip past initial place holders.
+ for (;; ++range->start) {
+
+ if (range->start >= buffer.used) {
+ state->status = F_okay_eos;
+
+ return;
+ }
+
+ if (range->start > range->stop) {
+ state->status = F_okay_stop;
+
+ return;
+ }
+
+ if (buffer.string[range->start] != f_fss_placeholder_s.string[0]) break;
+ } // for
+
uint8_t width = 0;
+ f_number_unsigned_t previous = range->start;
f_number_unsigned_t width_max = (range->stop - range->start) + 1;
if (width_max > buffer.used - range->start) {
f_fss_fail_utf_to_false(state);
if (state->status == F_false) break;
}
+ else {
+ // This is combining, so any previous white space is no longer considered white space as such.
+ range->start = previous;
+
+ // Ensure previous is not a place holder.
+ while (range->start && buffer.string[range->start] == f_fss_placeholder_s.string[0]) --range->start;
+
+ break;
+ }
}
}
if (F_status_is_error(state->status)) return;
+ previous = range->start;
+
width = macro_f_utf_byte_width(buffer.string[range->start]);
if (width > 1) {
extern void f_fss_seek_to_eol(const f_string_dynamic_t buffer, f_range_t * const range, f_state_t * const state);
#endif // _di_f_fss_seek_to_eol_
+/**
+ * Skip past all combining characters.
+ *
+ * This will do nothing if the first character is not a combining character.
+ *
+ * This skips past place holders.
+ *
+ * This stops on end of line.
+ *
+ * @param buffer
+ * The string to process.
+ * @param range
+ * The start and stop positions in the buffer being processed.
+ * This increments range->start.
+ * @param state
+ * A state for providing flags and handling interrupts during long running operations.
+ *
+ * This alters state.status:
+ * F_okay on success.
+ * F_data_not on success but buffer.used is 0, initial range.start is greater than range.stop, or initial range.start is greater than or equal to buffer.used.
+ * F_is_not on success, but the first character is not a combining character.
+ * F_okay_eol on success and EOL was reached.
+ * F_okay_eos on success and EOS was reached.
+ * F_okay_stop on success and stop point was reached.
+ *
+ * F_complete_not_utf_eos (with error bit) if unable to get entire UTF-8 sequence due to EOS.
+ * F_complete_not_utf_start (with error bit) if the first character is a combining character.
+ * F_complete_not_utf_stop (with error bit) if unable to get entire UTF-8 sequence due to stop point reached.
+ * F_parameter (with error bit) if a parameter is invalid.
+ *
+ * Errors (with error bit) from: f_utf_is_combining().
+ *
+ * @see f_utf_is_combining()
+ */
+#ifndef _di_f_fss_skip_past_combining_
+ extern void f_fss_skip_past_combining(const f_string_static_t buffer, f_range_t * const range, f_state_t * const state);
+#endif // _di_f_fss_skip_past_combining_
+
/**
* Skip past all delimit placeholders until a non-delimit placeholder is reached.
*
* If the first character in the given range is a combining character, then this will not skip past anything.
* This is because combining characters apply from right to left.
*
+ * White space is checked for combining characters after the white space.
+ * If there is a combining character after, then the white space is not consider as such.
+ *
+ * This skips past place holders.
+ *
+ * This stops on end of line.
+ *
* @param buffer
* The string to process.
* @param range
void private_fl_fss_basic_or_extended_read(const f_string_static_t buffer, const uint8_t flag, f_range_t * const range, f_range_t * const found, uint8_t * const quote, f_number_unsigneds_t * const delimits, f_state_t * const state) {
f_fss_skip_past_space(buffer, range, state);
- if (F_status_is_error(state->status) || state->status == F_data_not) return;
+
+ if (F_status_is_error(state->status) || state->status == F_data_not) {
+ if (F_status_set_fine(state->status) == F_complete_not_utf_start) {
+ f_fss_skip_past_combining(buffer, range, state);
+ if (F_status_is_error(state->status) || state->status == F_data_not) return;
+ }
+ else return;
+ }
if (state->status == F_okay_eol) {
// Move the start position to after the EOL.
void private_fl_fss_basic_write(const uint8_t flag, const f_string_static_t object, const uint8_t quote, f_range_t * const range, f_string_dynamic_t * const destination, f_state_t * const state, void * const internal) {
f_fss_skip_past_space(object, range, state);
- if (F_status_is_error(state->status) || state->status == F_data_not) return;
+
+ if (F_status_is_error(state->status) || state->status == F_data_not) {
+ if (F_status_set_fine(state->status) == F_complete_not_utf_start) {
+ f_fss_skip_past_combining(object, range, state);
+ if (F_status_is_error(state->status) || state->status == F_data_not) return;
+ }
+ else return;
+ }
if (state->status == F_okay_eos) {
state->status = F_data_not_eos;
* Errors (with error bit) from: f_fss_is_graph().
* Errors (with error bit) from: f_fss_is_space().
* Errors (with error bit) from: f_fss_is_zero_width().
+ * Errors (with error bit) from: f_fss_skip_past_combining().
* Errors (with error bit) from: f_fss_skip_past_delimit().
* Errors (with error bit) from: f_fss_skip_past_space().
* Errors (with error bit) from: f_utf_buffer_increment().
* @see f_fss_is_graph()
* @see f_fss_is_space()
* @see f_fss_is_zero_width()
+ * @see f_fss_skip_past_combining()
* @see f_fss_skip_past_delimit()
* @see f_fss_skip_past_space()
* @see f_utf_buffer_increment()
* F_parameter (with error bit) if a parameter is invalid.
*
* Errors (with error bit) from: f_fss_is_space().
+ * Errors (with error bit) from: f_fss_skip_past_combining().
* Errors (with error bit) from: f_fss_skip_past_delimit().
* Errors (with error bit) from: f_fss_skip_past_space().
* Errors (with error bit) from: f_memory_array_increase().
* Set to NULL to not use.
*
* @see f_fss_is_space()
+ * @see f_fss_skip_past_combining()
* @see f_fss_skip_past_delimit()
* @see f_fss_skip_past_space()
* @see f_memory_array_increase()
--- /dev/null
+valid.
+and does not have embedded new line.
+
+
+is valid.
+is valid with two combiners.
--- /dev/null
+2
+2
+1
+2
+2
+2
--- /dev/null
+first
+is_second
+́
+fourth ͜no_space
+fifth
+sixtẖ̚
--- /dev/null
+first valid.
+is_second and does not have embedded new line.
+́
+fourth ͜no_space
+fifth is valid.
+sixtẖ̚ is valid with two combiners.
}
}
+void test__fl_fss_basic_content_read__works_using_combining(void **void_state) {
+
+ {
+ // Note: These files are required to have the same number of lines and each line should probably be at max 255 characters.
+ FILE *file_contents = data__file_open__named("contents", "basic", "combining_read");
+ FILE *file_matches = data__file_open__named("matches", "basic", "combining_read");
+ FILE *file_strings = data__file_open__named("strings", "basic", "combining_read");
+
+ assert_non_null(file_contents);
+ assert_non_null(file_matches);
+ assert_non_null(file_strings);
+
+ int matches = 0;
+ size_t max = 0;
+ char *line_string = 0;
+ char *line_content = 0;
+ char *line_matches = 0;
+ ssize_t result = 0;
+
+ f_string_static_t buffer_string = f_string_static_t_initialize;
+
+ f_state_t state = f_state_t_initialize;
+ f_range_t range = f_range_t_initialize;
+ f_range_t found_object = f_range_t_initialize;
+ f_ranges_t found = f_ranges_t_initialize;
+ uint8_t quote = 0;
+ f_number_unsigneds_t delimits = f_number_unsigneds_t_initialize;
+ f_string_dynamic_t result_string = f_string_dynamic_t_initialize;
+ f_string_dynamic_t delimit_string = f_string_dynamic_t_initialize;
+ f_status_t status_object = F_okay;
+
+ for (;;) {
+
+ max = 255;
+
+ result = getline(&line_matches, &max, file_matches);
+ assert_return_code(result, 0);
+
+ matches = atoi(line_matches);
+
+ max = 255;
+
+ result = getline(&line_string, &max, file_strings);
+ if (result == -1) break;
+
+ buffer_string.string = line_string;
+ buffer_string.used = (f_number_unsigned_t) result;
+ buffer_string.size = buffer_string.used;
+
+ max = 255;
+
+ result = getline(&line_content, &max, file_contents);
+ assert_return_code(result, 0);
+
+ // The newline is copied by getline(), and so remove that newline before comparing.
+ line_content[result - 1] = 0;
+
+ state.status = F_none;
+ range.start = 0;
+ range.stop = buffer_string.used - 1;
+ found_object.start = 1;
+ found_object.stop = 0;
+
+ fl_fss_basic_object_read(buffer_string, &range, &found_object, "e, &delimits, &state);
+
+ if (matches) {
+ // When matches is 2, then this matches both object and content.
+ if (matches == 2) {
+ if (!(state.status == F_fss_found_object)) {
+ printf("[ -------> ] --- [00] Failure with line '%s', matches=%d, status=%u.\n", line_content, matches, state.status);
+ }
+
+ assert_true(state.status == F_fss_found_object);
+ }
+
+ // When matches is 1, then this matches only object.
+ else {
+ if (!(state.status == F_fss_found_object_content_not)) {
+ printf("[ -------> ] --- [02] Failure with line '%s', matches=%d, status=%u.\n", line_content, matches, state.status);
+ }
+
+ assert_true(state.status == F_fss_found_object_content_not);
+ }
+ }
+ else {
+
+ // This is currently not supported.
+ assert_true(F_false);
+ }
+
+ status_object = state.status;
+ state.status = F_none;
+
+ fl_fss_basic_content_read(buffer_string, &range, &found, &delimits, &state);
+
+ if (status_object == F_fss_found_object) {
+ if (!(status_object == F_fss_found_object)) {
+ printf("[ -------> ] --- [02] Failure with line '%s'.\n", line_content);
+ }
+
+ assert_int_equal(state.status, F_fss_found_content);
+ }
+ else {
+ if (state.status != F_data_not) {
+ printf("[ -------> ] --- [03] Failure with line '%s'.\n", line_content);
+ }
+
+ assert_int_equal(state.status, F_data_not);
+ }
+
+ if (matches == 2) {
+ if (state.status == F_fss_found_content) {
+ if (!found.used) {
+ printf("[ -------> ] --- [04] Failure with line '%s'.\n", line_content);
+ }
+
+ assert_true(found.used);
+
+ {
+ const f_status_t status = f_string_dynamic_append(buffer_string, &delimit_string);
+
+ if (status != F_okay) {
+ printf("[ -------> ] --- [05] Failure with line '%s'.\n", line_content);
+ }
+
+ assert_int_equal(status, F_okay);
+ }
+
+ state.status = F_none;
+
+ f_fss_apply_delimit(delimits, &delimit_string, &state);
+ assert_int_equal(state.status, F_okay);
+
+ {
+ const f_status_t status = f_string_dynamic_partial_append_nulless(delimit_string, found.array[0], &result_string);
+
+ if (!(status == F_okay || status == F_data_not_eos)) {
+ printf("[ -------> ] --- [06] Failure with line '%s', status=%u.\n", line_content, status);
+ }
+
+ assert_true(status == F_okay || status == F_data_not_eos);
+ }
+
+ {
+ const f_status_t status = f_string_dynamic_terminate_after(&result_string);
+
+ if (status != F_okay) {
+ printf("[ -------> ] --- [07] Failure with line '%s'.\n", line_content);
+ }
+
+ assert_int_equal(status, F_okay);
+ }
+
+ if (strcmp((const char *) result_string.string, (const char *) line_content)) {
+ printf("[ -------> ] --- [08] Failure with line '%s'; got '%s', expected '%s'.\n", line_content, result_string.string, line_content);
+ }
+
+ assert_string_equal(result_string.string, line_content);
+ }
+ else {
+ if (found.used) {
+ printf("[ -------> ] --- [09] Failure with line '%s'.\n", line_content);
+ }
+
+ assert_true(!found.used);
+ }
+ }
+
+ if (line_string) free(line_string);
+ if (line_content) free(line_content);
+ if (line_matches) free(line_matches);
+ if (result_string.string) free(result_string.string);
+ if (delimit_string.string) free(delimit_string.string);
+ if (delimits.array) free(delimits.array);
+ if (found.array) free(found.array);
+
+ line_string = 0;
+ line_content = 0;
+ line_matches = 0;
+ result_string.string = 0;
+ result_string.used = 0;
+ result_string.size = 0;
+ delimit_string.string = 0;
+ delimit_string.used = 0;
+ delimit_string.size = 0;
+ delimits.array = 0;
+ delimits.used = 0;
+ delimits.size = 0;
+ found.array = 0;
+ found.used = 0;
+ found.size = 0;
+ } // for
+
+ if (file_strings) fclose(file_strings);
+ if (file_contents) fclose(file_contents);
+ if (file_matches) fclose(file_matches);
+
+ if (delimits.array) free(delimits.array);
+ if (found.array) free(found.array);
+ if (line_string) free(line_string);
+ if (line_content) free(line_content);
+ if (line_matches) free(line_matches);
+ if (result_string.string) free(result_string.string);
+ if (delimit_string.string) free(delimit_string.string);
+ }
+}
+
#ifdef __cplusplus
} // extern "C"
#endif
*/
extern void test__fl_fss_basic_content_read__works(void **state);
+/**
+ * Test that the function works when using combining characters.
+ *
+ * @see fl_fss_basic_content_read()
+ */
+extern void test__fl_fss_basic_content_read__works_using_combining(void **state);
+
#endif // _TEST__FL_fss_basic_content_read_h
}
}
+void test__fl_fss_basic_object_read__works_using_combining(void **void_state) {
+
+ {
+ // Note: These files are required to have the same number of lines and each line should probably be at max 255 characters.
+ FILE *file_matches = data__file_open__named("matches", "basic", "combining_read");
+ FILE *file_objects = data__file_open__named("objects", "basic", "combining_read");
+ FILE *file_strings = data__file_open__named("strings", "basic", "combining_read");
+
+ assert_non_null(file_matches);
+ assert_non_null(file_objects);
+ assert_non_null(file_strings);
+
+ int matches = 0;
+ size_t max = 0;
+ char *line_matches = 0;
+ char *line_object = 0;
+ char *line_string = 0;
+ ssize_t result = 0;
+
+ f_string_static_t buffer_string = f_string_static_t_initialize;
+
+ f_state_t state = f_state_t_initialize;
+ f_range_t range = f_range_t_initialize;
+ f_range_t found = f_range_t_initialize;
+ uint8_t quote = 0;
+ f_number_unsigneds_t delimits = f_number_unsigneds_t_initialize;
+ f_string_dynamic_t result_string = f_string_dynamic_t_initialize;
+ f_string_dynamic_t delimit_string = f_string_dynamic_t_initialize;
+
+ for (;;) {
+
+ max = 255;
+
+ result = getline(&line_matches, &max, file_matches);
+ assert_return_code(result, 0);
+
+ matches = atoi(line_matches);
+
+ max = 255;
+
+ result = getline(&line_string, &max, file_strings);
+ if (result == -1) break;
+
+ buffer_string.string = line_string;
+ buffer_string.used = (f_number_unsigned_t) result;
+ buffer_string.size = buffer_string.used;
+
+ max = 255;
+
+ result = getline(&line_object, &max, file_objects);
+ assert_return_code(result, 0);
+
+ // The newline is copied by getline(), and so remove that newline before comparing.
+ line_object[result - 1] = 0;
+
+ state.status = F_none;
+ range.start = 0;
+ range.stop = buffer_string.used - 1;
+ found.start = 1;
+ found.stop = 0;
+
+ fl_fss_basic_object_read(buffer_string, &range, &found, "e, &delimits, &state);
+
+ if (matches) {
+ // When matches is 2, then this matches both object and content.
+ if (matches == 2) {
+ if (!(state.status == F_fss_found_object)) {
+ printf("[ -------> ] --- [00] Failure with line '%s', matches=%d, status=%u.\n", line_object, matches, state.status);
+ }
+
+ assert_true(state.status == F_fss_found_object);
+
+ if (!(found.start <= found.stop)) {
+ printf("[ -------> ] --- [01] Failure with line '%s', matches=%d, found=(%lu, %lu).\n", line_object, matches, found.start, found.stop);
+ }
+
+ assert_true(found.start <= found.stop);
+ }
+
+ // When matches is 1, then this matches only object.
+ else {
+ if (!(state.status == F_fss_found_object_content_not)) {
+ printf("[ -------> ] --- [02] Failure with line '%s', matches=%d, status=%u.\n", line_object, matches, state.status);
+ }
+
+ assert_true(state.status == F_fss_found_object_content_not);
+ }
+ }
+ else {
+
+ // This is currently not supported.
+ assert_true(F_false);
+ }
+
+
+ {
+ const f_status_t status = f_string_dynamic_append(buffer_string, &delimit_string);
+
+ if (status != F_okay) {
+ printf("[ -------> ] --- [03] Failure with line '%s'.\n", line_object);
+ }
+
+ assert_int_equal(status, F_okay);
+ }
+
+ state.status = F_none;
+
+ f_fss_apply_delimit(delimits, &delimit_string, &state);
+
+ if (state.status != F_okay) {
+ printf("[ -------> ] --- [04] Failure with line '%s'.\n", line_object);
+ }
+
+ assert_int_equal(state.status, F_okay);
+
+ {
+ const f_status_t status = f_string_dynamic_partial_append_nulless(delimit_string, found, &result_string);
+
+ if (!(status == F_okay || status == F_data_not_eos)) {
+ printf("[ -------> ] --- [05] Failure with line '%s', status=%u.\n", line_object, status);
+ }
+
+ assert_true(status == F_okay || status == F_data_not_eos);
+ }
+
+ {
+ const f_status_t status = f_string_dynamic_terminate_after(&result_string);
+
+ if (status != F_okay) {
+ printf("[ -------> ] --- [06] Failure with line '%s'.\n", line_object);
+ }
+
+ assert_int_equal(status, F_okay);
+ }
+
+ if (strcmp((const char *) result_string.string, (const char *) line_object)) {
+ printf("[ -------> ] --- [07] Failure with line '%s'.\n", line_object);
+ }
+
+ assert_string_equal(result_string.string, line_object);
+
+ if (line_matches) free(line_matches);
+ if (line_object) free(line_object);
+ if (line_string) free(line_string);
+ if (result_string.string) free(result_string.string);
+ if (delimit_string.string) free(delimit_string.string);
+ if (delimits.array) free(delimits.array);
+
+ line_matches = 0;
+ line_object = 0;
+ line_string = 0;
+ result_string.string = 0;
+ result_string.used = 0;
+ result_string.size = 0;
+ delimit_string.string = 0;
+ delimit_string.used = 0;
+ delimit_string.size = 0;
+ delimits.array = 0;
+ delimits.used = 0;
+ delimits.size = 0;
+ } // for
+
+ if (file_matches) fclose(file_matches);
+ if (file_objects) fclose(file_objects);
+ if (file_strings) fclose(file_strings);
+
+ if (delimits.array) free(delimits.array);
+ if (line_string) free(line_string);
+ if (line_object) free(line_object);
+ if (result_string.string) free(result_string.string);
+ if (delimit_string.string) free(delimit_string.string);
+ }
+}
+
+
#ifdef __cplusplus
} // extern "C"
#endif
*/
extern void test__fl_fss_basic_object_read__works(void **state);
+/**
+ * Test that the function works when using combining characters.
+ *
+ * @see fl_fss_basic_object_read()
+ */
+extern void test__fl_fss_basic_object_read__works_using_combining(void **state);
+
#endif // _TEST__FL_fss_basic_object_read_h
cmocka_unit_test(test__fl_fss_basic_object_write__returns_data_not),
cmocka_unit_test(test__fl_fss_basic_content_read__works),
+ cmocka_unit_test(test__fl_fss_basic_content_read__works_using_combining),
cmocka_unit_test(test__fl_fss_basic_object_read__works),
+ cmocka_unit_test(test__fl_fss_basic_object_read__works_using_combining),
cmocka_unit_test(test__fl_fss_basic_list_content_read__returns_data_not),
cmocka_unit_test(test__fl_fss_basic_list_content_write__returns_data_not),