From 23abde0295b1c10bb170cf9a5f164a781ee08d6f Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sun, 11 Oct 2020 22:46:06 -0500 Subject: [PATCH] Update: basic list fixes and cleanups, including some other cleanups. The EOL handling in FSS Basic List is incorrect/incomplete. Slashes at the end of an Object must be delimited to avoid escaping the object close character. Be sure to return an error when a newline is provided in an Object name on basic list object write. The standard states that controlling character, such as a basic list open, must use ASCII character codes for simplicity and safety. Therefore, a UTF-8 buffer increment is not necessary. Use the simpler, more performant C math operator increment. Cleanup coding strategy in basic list content write to be more consistent with more recent approaches. Cleanup some comments. Also cleanup incorrect loop comment in fss_basic.c. --- level_1/fl_fss/c/fss_basic.c | 2 +- level_1/fl_fss/c/fss_basic_list.c | 172 ++++++++++----------- .../c/private-fss_basic_list_write.c | 20 +++ .../c/private-fss_basic_list_write.h | 14 ++ 4 files changed, 120 insertions(+), 88 deletions(-) diff --git a/level_1/fl_fss/c/fss_basic.c b/level_1/fl_fss/c/fss_basic.c index af633f8..bae4c1e 100644 --- a/level_1/fl_fss/c/fss_basic.c +++ b/level_1/fl_fss/c/fss_basic.c @@ -169,7 +169,7 @@ extern "C" { } destination->string[destination->used++] = content.string[range->start]; - } // while + } // for if (complete == f_fss_complete_full || complete == f_fss_complete_end) { destination->string[destination->used++] = f_fss_basic_close; diff --git a/level_1/fl_fss/c/fss_basic_list.c b/level_1/fl_fss/c/fss_basic_list.c index 2c47a01..50e0bf4 100644 --- a/level_1/fl_fss/c/fss_basic_list.c +++ b/level_1/fl_fss/c/fss_basic_list.c @@ -466,18 +466,18 @@ extern "C" { break; } - if (object.string[range->start] == f_fss_eol) { - status = F_status_set_error(F_none_eol); - break; - } - status = f_fss_is_graph(object, *range); if (F_status_is_error(status)) break; if (status == F_true) break; - // objects will not have leading whitespaces, but having this does not generate an invalid object, so just write the spaces. + // objects will not have leading whitespaces, but having this does not result in an invalid object, so just write the provided spaces. if (object.string[range->start] != f_fss_delimit_placeholder) { + if (object.string[range->start] == f_fss_eol) { + status = F_status_set_error(F_none_eol); + break; + } + status = f_fss_is_space(object, *range); if (F_status_is_error(status)) break; @@ -520,6 +520,12 @@ extern "C" { if (F_status_is_error(status)) break; + if (range->start > range->stop || range->start >= object.used) { + + // slashes at the end of the object must be delimited to avoid delimiting the object close character. + slash_count *= 2; + } + status = private_fl_fss_destination_increase_by(slash_count, destination); if (F_status_is_error(status)) break; @@ -531,15 +537,13 @@ extern "C" { break; } } - else if (object.string[range->start] == f_fss_eol) { - if (destination->used == used_start) { - return F_data_not_eol; - } - - return F_none_eol; - } if (object.string[range->start] != f_fss_delimit_placeholder) { + if (object.string[range->start] == f_fss_eol) { + status = F_status_set_error(F_none_eol); + break; + } + width = f_macro_utf_byte_width(object.string[range->start]); status = private_fl_fss_destination_increase_by(width, destination); @@ -560,6 +564,13 @@ extern "C" { } if (complete == f_fss_complete_partial || complete == f_fss_complete_full) { + status = private_fl_fss_destination_increase_by(2, destination); + + if (F_status_is_error(status)) { + destination->used = used_start; + return status; + } + destination->string[destination->used++] = f_fss_basic_list_open; destination->string[destination->used++] = f_fss_eol; } @@ -584,82 +595,59 @@ extern "C" { #endif // _di_level_1_parameter_checking_ f_status_t status = F_none; - bool is_comment = F_false; - bool has_graph = F_false; - - f_string_range_t buffer_position = f_string_range_t_initialize; - f_string_length_t start_position = f_string_t_initialize; - f_string_length_t size_allocate = 0; - f_string_length_t slash_count = 0; - f_string_length_t start = 0; fl_macro_fss_skip_past_delimit_placeholders(content, (*range)); if (range->start > range->stop) { - if (destination->used + f_fss_default_allocation_step > f_string_length_t_size) { - if (destination->used + 1 > f_string_length_t_size) { - return F_status_set_error(F_string_too_large); - } - - f_macro_string_dynamic_t_resize(status, (*destination), destination->used + 1); - if (F_status_is_error(status)) return status; - } - else { - f_macro_string_dynamic_t_resize(status, (*destination), destination->used + f_fss_default_allocation_step); - if (F_status_is_error(status)) return status; - } - - destination->string[destination->used++] = f_fss_extended_close; - return F_data_not_stop; + status = F_data_not_stop; + } + else if (range->start >= content.used) { + status = F_data_not_eos; } - if (range->start >= content.used) { - return F_data_not_eos; + if (status == F_data_not_stop || status == F_data_not_eos) { + return status; } - start_position = range->start; + // ensure that there is room for a slash delimit and possibly the end of line character. + status = private_fl_fss_destination_increase_by(destination->used + (range->stop - range->start) + 2, destination); + if (F_status_is_error(status)) return status; - // add an additional 2 to ensure that there is room for the slash delimit and the content open character. - size_allocate = destination->used + (range->stop - range->start) + 2 + f_fss_default_allocation_step; + const f_string_length_t input_start = range->start; + const f_string_length_t used_start = destination->used; - if (size_allocate > destination->size) { - f_macro_string_dynamic_t_resize(status, (*destination), size_allocate); - if (F_status_is_error(status)) return status; - } + bool is_comment = F_false; + bool has_graph = F_false; + + f_string_length_t i = 0; + f_string_length_t slash_count = 0; + f_string_length_t start = 0; - buffer_position.start = destination->used; - buffer_position.stop = destination->used; + uint8_t width = 0; while (range->start <= range->stop && range->start < content.used) { if (content.string[range->start] == f_fss_delimit_slash && !is_comment) { slash_count = 1; - destination->string[buffer_position.stop++] = content.string[range->start]; + destination->string[destination->used++] = content.string[range->start]; has_graph = F_true; status = f_utf_buffer_increment(content, range, 1); if (F_status_is_error(status)) return status; - while (range->start <= range->stop && range->start < content.used) { + for (; range->start <= range->stop && range->start < content.used; range->start++) { if (content.string[range->start] == f_fss_delimit_placeholder) { - status = f_utf_buffer_increment(content, range, 1); - if (F_status_is_error(status)) return status; - continue; } else if (content.string[range->start] != f_fss_delimit_slash) { break; } - destination->string[buffer_position.stop++] = content.string[range->start]; - - status = f_utf_buffer_increment(content, range, 1); - if (F_status_is_error(status)) return status; - + destination->string[destination->used++] = f_fss_delimit_slash; slash_count++; - } // while + } // for if (content.string[range->start] == f_fss_basic_list_open) { start = range->start; @@ -669,7 +657,7 @@ extern "C" { while (range->start < content.used && range->start <= range->stop) { - if (content.string[range->start] == f_string_eol[0]) break; + if (content.string[range->start] == f_fss_eol) break; status = f_fss_is_space(content, *range); if (F_status_is_error(status)) return status; @@ -680,38 +668,37 @@ extern "C" { if (F_status_is_error(status)) return status; } // while - if (content.string[range->start] == f_string_eol[0] || range->start >= content.used || range->start > range->stop) { - size_allocate += slash_count + 1; + if (content.string[range->start] == f_fss_eol || range->start >= content.used || range->start > range->stop) { - if (size_allocate > destination->size) { - f_macro_string_dynamic_t_resize(status, (*destination), size_allocate + f_fss_default_allocation_step); - if (F_status_is_error(status)) return status; - } + // increase by total slashes + 1, along with the basic list open. + status = private_fl_fss_destination_increase_by(slash_count + 2, destination); + if (F_status_is_error(status)) return status; while (slash_count--) { - destination->string[buffer_position.stop++] = f_fss_delimit_slash; + destination->string[destination->used++] = f_fss_delimit_slash; } // while - destination->string[buffer_position.stop++] = f_fss_delimit_slash; + destination->string[destination->used++] = f_fss_delimit_slash; has_graph = F_false; is_comment = F_false; } + else { + status = private_fl_fss_destination_increase(destination); + if (F_status_is_error(status)) return status; + } - destination->string[buffer_position.stop++] = f_fss_basic_list_open; + destination->string[destination->used++] = f_fss_basic_list_open; range->start = start + 1; continue; } } else if (content.string[range->start] == f_fss_basic_list_open && !is_comment) { - start = range->start; + start = range->start++; has_graph = F_true; - status = f_utf_buffer_increment(content, range, 1); - if (F_status_is_error(status)) return status; - while (range->start < content.used && range->start <= range->stop) { - if (content.string[range->start] == f_string_eol[0]) break; + if (content.string[range->start] == f_fss_eol) break; status = f_fss_is_space(content, *range); if (F_status_is_error(status)) return status; @@ -722,27 +709,29 @@ extern "C" { if (F_status_is_error(status)) return status; } // while - if (content.string[range->start] == f_string_eol[0] || range->start >= content.used || range->start > range->stop) { - size_allocate++; + if (content.string[range->start] == f_fss_eol || range->start >= content.used || range->start > range->stop) { - if (size_allocate > destination->size) { - f_macro_string_dynamic_t_resize(status, (*destination), size_allocate + f_fss_default_allocation_step); - if (F_status_is_error(status)) return status; - } + // increase by slash and basic list open. + status = private_fl_fss_destination_increase_by(2, destination); + if (F_status_is_error(status)) return status; - destination->string[buffer_position.stop++] = f_fss_delimit_slash; + destination->string[destination->used++] = f_fss_delimit_slash; has_graph = F_false; is_comment = F_false; } + else { + status = private_fl_fss_destination_increase(destination); + if (F_status_is_error(status)) return status; + } - destination->string[buffer_position.stop++] = f_fss_basic_list_open; + destination->string[destination->used++] = f_fss_basic_list_open; range->start = start + 1; continue; } else if (content.string[range->start] == f_fss_comment && !has_graph) { is_comment = F_true; } - else if (content.string[range->start] == f_string_eol[0]) { + else if (content.string[range->start] == f_fss_eol) { has_graph = F_false; is_comment = F_false; } @@ -754,18 +743,27 @@ extern "C" { } if (content.string[range->start] != f_fss_delimit_placeholder) { - destination->string[buffer_position.stop++] = content.string[range->start]; + width = f_macro_utf_byte_width(content.string[range->start]); + + status = private_fl_fss_destination_increase_by(width, destination); + if (F_status_is_error(status)) break; + + for (i = 0; i < width; i++) { + destination->string[destination->used++] = content.string[range->start + i]; + } // for } status = f_utf_buffer_increment(content, range, 1); if (F_status_is_error(status)) return status; } // while - destination->string[buffer_position.stop] = f_string_eol[0]; - destination->used = buffer_position.stop + 1; + if (range->start > range->stop) { + return F_none_stop; + } - if (range->start > range->stop) return F_none_stop; - else if (range->start >= content.used) return F_none_eos; + if (range->start >= content.used) { + return F_none_eos; + } return F_none; } diff --git a/level_3/fss_basic_list_write/c/private-fss_basic_list_write.c b/level_3/fss_basic_list_write/c/private-fss_basic_list_write.c index 95324ee..564831a 100644 --- a/level_3/fss_basic_list_write/c/private-fss_basic_list_write.c +++ b/level_3/fss_basic_list_write/c/private-fss_basic_list_write.c @@ -23,6 +23,20 @@ extern "C" { } #endif // _di_fss_basic_list_write_error_parameter_same_times_print_ +#ifndef _di_fss_basic_list_write_error_parameter_unsupported_eol_print_ + void fss_basic_list_write_error_parameter_unsupported_eol_print(const fss_basic_list_write_data_t data) { + + if (data.error.verbosity == f_console_verbosity_quiet) { + return; + } + + fprintf(data.error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data.error.to.stream, data.context.set.error, "%sThis standard does not support end of line character '", fll_error_print_error); + fl_color_print(data.error.to.stream, data.context.set.notable, "\\n"); + fl_color_print(data.error.to.stream, data.context.set.error, "' in objects.%c", f_string_eol[0]); + } +#endif // _di_fss_basic_list_write_error_parameter_unsupported_eol_print_ + #ifndef _di_fss_basic_list_write_error_parameter_value_missing_print_ void fss_basic_list_write_error_parameter_value_missing_print(const fss_basic_list_write_data_t data, const f_string_t symbol, const f_string_t parameter) { @@ -55,6 +69,12 @@ extern "C" { status = fl_fss_basic_list_object_write(*object, content ? f_fss_complete_full : f_fss_complete_partial, &range, buffer); + if (F_status_set_fine(status) == F_none_eol) { + fss_basic_list_write_error_parameter_unsupported_eol_print(data); + + return F_status_set_error(F_unsupported); + } + if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "fl_fss_basic_list_object_write", F_true); return status; diff --git a/level_3/fss_basic_list_write/c/private-fss_basic_list_write.h b/level_3/fss_basic_list_write/c/private-fss_basic_list_write.h index bb18a92..9a9a7eb 100644 --- a/level_3/fss_basic_list_write/c/private-fss_basic_list_write.h +++ b/level_3/fss_basic_list_write/c/private-fss_basic_list_write.h @@ -27,6 +27,20 @@ extern "C" { #endif // _di_fss_basic_list_write_error_parameter_same_times_print_ /** + * Print an message about a parameter EOL being unsupported. + * + * @param data + * The program data. + * + * @return + * F_none on success. + * F_failure (with error bit) for any othe failure. + */ +#ifndef _di_fss_basic_list_write_error_parameter_unsupported_eol_print_ + void fss_basic_list_write_error_parameter_unsupported_eol_print(const fss_basic_list_write_data_t data) f_gcc_attribute_visibility_internal; +#endif // _di_fss_basic_list_write_error_parameter_unsupported_eol_print_ + +/** * Print an message about a parameter missing a value. * * @param data -- 1.8.3.1