From bf44dacb5bd73700a7a0103aa8c5a6f2774997de Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Mon, 12 Oct 2020 20:07:50 -0500 Subject: [PATCH] Progress: FSS write programs. Add prepend functionality to all write programs. - for FSS-0000 (Basic) and FSS-0001 (Extended), this does nothing. - for FSS-0002 (Basic List) and FSS-0003 (Extended List), this prepends the start of multi-line content with some whitespace. Begin working on the FSS-0003 (Extended List) write functions and programs. - At this time, the extended list write is only implemented partially. - I will focus on the recursive aspects later. Add the "complete" processing to the basic list content (and now extended list content) write functions. - Includes updates to the newline handling as appropriate. Update documentation comments. --- level_0/f_fss/c/fss-common.h | 3 +- level_1/fl_fss/c/fss_basic.h | 8 +- level_1/fl_fss/c/fss_basic_list.c | 123 ++++-- level_1/fl_fss/c/fss_basic_list.h | 12 +- level_1/fl_fss/c/fss_extended.h | 8 +- level_1/fl_fss/c/fss_extended_list.c | 447 +++++++++++++------- level_1/fl_fss/c/fss_extended_list.h | 19 +- level_1/fl_fss/c/private-fss.c | 28 +- level_1/fl_fss/c/private-fss.h | 37 +- level_2/fll_fss/c/fss_basic_list.c | 4 +- level_2/fll_fss/c/fss_basic_list.h | 5 +- .../fss_basic_list_write/c/fss_basic_list_write.c | 60 ++- .../fss_basic_list_write/c/fss_basic_list_write.h | 8 +- .../c/private-fss_basic_list_write.c | 13 +- level_3/fss_basic_write/c/fss_basic_write.c | 64 ++- level_3/fss_basic_write/c/fss_basic_write.h | 6 +- .../fss_basic_write/c/private-fss_basic_write.c | 8 +- .../c/fss_extended_list_write.c | 467 +++++++++++++++++++++ .../c/fss_extended_list_write.h | 204 +++++++++ level_3/fss_extended_list_write/c/main.c | 16 + .../c/private-fss_extended_list_write.c | 266 ++++++++++++ .../c/private-fss_extended_list_write.h | 111 +++++ level_3/fss_extended_list_write/data/build/defines | 2 + .../data/build/dependencies | 26 ++ .../fss_extended_list_write/data/build/settings | 56 +++ level_3/fss_extended_write/c/fss_extended_write.c | 78 +++- level_3/fss_extended_write/c/fss_extended_write.h | 8 +- .../c/private-fss_extended_write.c | 15 +- 28 files changed, 1873 insertions(+), 229 deletions(-) create mode 100644 level_3/fss_extended_list_write/c/fss_extended_list_write.c create mode 100644 level_3/fss_extended_list_write/c/fss_extended_list_write.h create mode 100644 level_3/fss_extended_list_write/c/main.c create mode 100644 level_3/fss_extended_list_write/c/private-fss_extended_list_write.c create mode 100644 level_3/fss_extended_list_write/c/private-fss_extended_list_write.h create mode 100644 level_3/fss_extended_list_write/data/build/defines create mode 100644 level_3/fss_extended_list_write/data/build/dependencies create mode 100644 level_3/fss_extended_list_write/data/build/settings diff --git a/level_0/f_fss/c/fss-common.h b/level_0/f_fss/c/fss-common.h index 49a40a5..89d5f0f 100644 --- a/level_0/f_fss/c/fss-common.h +++ b/level_0/f_fss/c/fss-common.h @@ -29,10 +29,11 @@ extern "C" { #define f_fss_extended_open ' ' #define f_fss_extended_next ' ' #define f_fss_extended_close f_string_eol[0] - #define f_fss_list_terminator f_string_eol[0] #define f_fss_basic_list_open ':' + #define f_fss_basic_list_open_end f_string_eol[0] #define f_fss_basic_list_close f_string_eol[0] #define f_fss_extended_list_open '{' + #define f_fss_extended_list_open_end f_string_eol[0] #define f_fss_extended_list_close '}' #define f_fss_extended_list_close_end f_string_eol[0] #define f_fss_type_header_open '#' diff --git a/level_1/fl_fss/c/fss_basic.h b/level_1/fl_fss/c/fss_basic.h index 99ac0ae..d474c87 100644 --- a/level_1/fl_fss/c/fss_basic.h +++ b/level_1/fl_fss/c/fss_basic.h @@ -174,9 +174,11 @@ extern "C" { * @param content * The string to write as (does not stop at NULLS, they are ignored and not written). * @param complete - * If f_fss_complete_none, then only the object name is written. - * If f_fss_complete_partial, this will write any appropriate open and close aspects of this object, except for the final newline. - * If f_fss_complete_full, this will write any appropriate open and close aspects of this object, including the final newline. + * If f_fss_complete_none, then only the content is written. + * If f_fss_complete_next, then the content followed by any appropriate "next" character separating one content from the next, if applicable. + * If f_fss_complete_end, then the content followed by any appropriate "end" character designating the last content for some object, printing final newline, if applicable. + * If f_fss_complete_partial, this will write any appropriate open and close aspects of this content, except for the final newline. + * If f_fss_complete_full, this will write any appropriate open and close aspects of this content, including the final newline. * @param range * The start/stop location within the content string to write as an content. * @param destination diff --git a/level_1/fl_fss/c/fss_basic_list.c b/level_1/fl_fss/c/fss_basic_list.c index 50e0bf4..cf55220 100644 --- a/level_1/fl_fss/c/fss_basic_list.c +++ b/level_1/fl_fss/c/fss_basic_list.c @@ -432,7 +432,7 @@ extern "C" { destination->string[destination->used++] = f_fss_basic_list_open; if (complete == f_fss_complete_full) { - destination->string[destination->used++] = f_fss_eol; + destination->string[destination->used++] = f_fss_basic_list_open_end; } } @@ -572,7 +572,10 @@ extern "C" { } destination->string[destination->used++] = f_fss_basic_list_open; - destination->string[destination->used++] = f_fss_eol; + + if (complete == f_fss_complete_full) { + destination->string[destination->used++] = f_fss_basic_list_open_end; + } } if (range->start > range->stop) { @@ -588,7 +591,7 @@ extern "C" { #endif // _di_fl_fss_basic_list_object_write_ #ifndef _di_fl_fss_basic_list_content_write_ - f_return_status fl_fss_basic_list_content_write(const f_string_static_t content, f_string_range_t *range, f_string_dynamic_t *destination) { + f_return_status fl_fss_basic_list_content_write(const f_string_static_t content, const uint8_t complete, const f_string_static_t prepend, f_string_range_t *range, f_string_dynamic_t *destination) { #ifndef _di_level_1_parameter_checking_ if (!range) return F_status_set_error(F_parameter); if (!destination) return F_status_set_error(F_parameter); @@ -598,18 +601,22 @@ extern "C" { fl_macro_fss_skip_past_delimit_placeholders(content, (*range)); - if (range->start > range->stop) { - status = F_data_not_stop; - } - else if (range->start >= content.used) { - status = F_data_not_eos; - } + if (range->start > range->stop || range->start >= content.used) { + if (complete == f_fss_complete_full || complete == f_fss_complete_end) { + status = private_fl_fss_destination_increase(destination); + if (F_status_is_error(status)) return status; - if (status == F_data_not_stop || status == F_data_not_eos) { - return status; + destination->string[destination->used++] = f_fss_basic_list_close; + } + + if (range->start > range->stop) { + return F_data_not_stop; + } + + return F_data_not_eos; } - // ensure that there is room for a slash delimit and possibly the end of line character. + // ensure that there is room for a slash delimit and possibly the end of content character. status = private_fl_fss_destination_increase_by(destination->used + (range->stop - range->start) + 2, destination); if (F_status_is_error(status)) return status; @@ -618,6 +625,7 @@ extern "C" { bool is_comment = F_false; bool has_graph = F_false; + bool do_prepend = F_true; f_string_length_t i = 0; f_string_length_t slash_count = 0; @@ -630,11 +638,18 @@ extern "C" { if (content.string[range->start] == f_fss_delimit_slash && !is_comment) { slash_count = 1; + if (do_prepend) { + status = private_fl_fss_destination_prepend(prepend, destination); + if (F_status_is_error(status)) break; + + do_prepend = F_false; + } + 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; + if (F_status_is_error(status)) break; for (; range->start <= range->stop && range->start < content.used; range->start++) { @@ -653,26 +668,31 @@ extern "C" { start = range->start; status = f_utf_buffer_increment(content, range, 1); - if (F_status_is_error(status)) return status; + if (F_status_is_error(status)) break; while (range->start < content.used && range->start <= range->stop) { - if (content.string[range->start] == f_fss_eol) break; + if (content.string[range->start] == f_fss_eol) { + do_prepend = F_true; + break; + } status = f_fss_is_space(content, *range); - if (F_status_is_error(status)) return status; + if (F_status_is_error(status)) break; if (status == F_false) break; status = f_utf_buffer_increment(content, range, 1); - if (F_status_is_error(status)) return status; + if (F_status_is_error(status)) break; } // while + if (F_status_is_error(status)) break; + if (content.string[range->start] == f_fss_eol || range->start >= content.used || range->start > range->stop) { - // 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; + // increase by total slashes + 1, along with the basic list open and possible newline. + status = private_fl_fss_destination_increase_by(slash_count + 3, destination); + if (F_status_is_error(status)) break; while (slash_count--) { destination->string[destination->used++] = f_fss_delimit_slash; @@ -684,10 +704,15 @@ extern "C" { } else { status = private_fl_fss_destination_increase(destination); - if (F_status_is_error(status)) return status; + if (F_status_is_error(status)) break; } destination->string[destination->used++] = f_fss_basic_list_open; + + if (content.string[range->start] == f_fss_eol) { + destination->string[destination->used++] = f_fss_eol; + } + range->start = start + 1; continue; } @@ -701,19 +726,31 @@ extern "C" { if (content.string[range->start] == f_fss_eol) break; status = f_fss_is_space(content, *range); - if (F_status_is_error(status)) return status; + if (F_status_is_error(status)) break; if (status == F_false) break; status = f_utf_buffer_increment(content, range, 1); - if (F_status_is_error(status)) return status; + if (F_status_is_error(status)) break; } // while + if (F_status_is_error(status)) break; + + if (do_prepend) { + status = private_fl_fss_destination_prepend(prepend, destination); + if (F_status_is_error(status)) break; + + do_prepend = F_false; + } + if (content.string[range->start] == f_fss_eol || range->start >= content.used || range->start > range->stop) { + if (content.string[range->start] == f_fss_eol) { + do_prepend = F_true; + } - // increase by slash and basic list open. - status = private_fl_fss_destination_increase_by(2, destination); - if (F_status_is_error(status)) return status; + // increase by slash and basic list open and possible newline. + status = private_fl_fss_destination_increase_by(3, destination); + if (F_status_is_error(status)) break; destination->string[destination->used++] = f_fss_delimit_slash; has_graph = F_false; @@ -721,10 +758,15 @@ extern "C" { } else { status = private_fl_fss_destination_increase(destination); - if (F_status_is_error(status)) return status; + if (F_status_is_error(status)) break; } destination->string[destination->used++] = f_fss_basic_list_open; + + if (content.string[range->start] == f_fss_eol) { + destination->string[destination->used++] = f_fss_eol; + } + range->start = start + 1; continue; } @@ -739,10 +781,21 @@ extern "C" { has_graph = F_true; } else if (F_status_is_error(status)) { - return status; + break; } if (content.string[range->start] != f_fss_delimit_placeholder) { + if (do_prepend) { + status = private_fl_fss_destination_prepend(prepend, destination); + if (F_status_is_error(status)) break; + + do_prepend = F_false; + } + + if (content.string[range->start] == f_fss_eol) { + do_prepend = F_true; + } + width = f_macro_utf_byte_width(content.string[range->start]); status = private_fl_fss_destination_increase_by(width, destination); @@ -754,9 +807,21 @@ extern "C" { } status = f_utf_buffer_increment(content, range, 1); - if (F_status_is_error(status)) return status; + if (F_status_is_error(status)) break; } // while + if (F_status_is_error(status)) { + destination->used = used_start; + return status; + } + + if (complete == f_fss_complete_full || complete == f_fss_complete_end) { + status = private_fl_fss_destination_increase(destination); + if (F_status_is_error(status)) return status; + + destination->string[destination->used++] = f_fss_basic_list_close; + } + if (range->start > range->stop) { return F_none_stop; } diff --git a/level_1/fl_fss/c/fss_basic_list.h b/level_1/fl_fss/c/fss_basic_list.h index 05a1ded..02d3f96 100644 --- a/level_1/fl_fss/c/fss_basic_list.h +++ b/level_1/fl_fss/c/fss_basic_list.h @@ -166,6 +166,16 @@ extern "C" { * * @param content * The string to write as (does not stop at NULLS, they are ignored and not written). + * @param complete + * If f_fss_complete_none, then only the content is written. + * If f_fss_complete_next, then the content followed by any appropriate "next" character separating one content from the next, if applicable. + * If f_fss_complete_end, then the content followed by any appropriate "end" character designating the last content for some object, printing final newline, if applicable. + * If f_fss_complete_partial, this will write any appropriate open and close aspects of this content, except for the final newline. + * If f_fss_complete_full, this will write any appropriate open and close aspects of this content, including the final newline. + * @param prepend + * A string of whitespace to prepend at the start of each line. + * This should only be whitespace, anything else could product invalid content. + * Set prepend.used to 0 to not use. * @param range * The start/stop location within the content string to write as an content. * @param destination @@ -186,7 +196,7 @@ extern "C" { * Errors (with error bit) from: f_utf_buffer_increment(). */ #ifndef _di_fl_fss_basic_list_content_write_ - extern f_return_status fl_fss_basic_list_content_write(const f_string_static_t content, f_string_range_t *range, f_string_dynamic_t *destination); + extern f_return_status fl_fss_basic_list_content_write(const f_string_static_t content, const uint8_t complete, const f_string_static_t prepend, f_string_range_t *range, f_string_dynamic_t *destination); #endif // _di_fl_fss_basic_list_content_write_ #ifdef __cplusplus diff --git a/level_1/fl_fss/c/fss_extended.h b/level_1/fl_fss/c/fss_extended.h index 4976456..9d3dae1 100644 --- a/level_1/fl_fss/c/fss_extended.h +++ b/level_1/fl_fss/c/fss_extended.h @@ -180,9 +180,11 @@ extern "C" { * If 0, then double quotes are auto-inserted, when required. * Otherwise, this is the type of quote to wrap the object in when writing. * @param complete - * If f_fss_complete_none, then only the object name is written. - * If f_fss_complete_partial, this will write any appropriate open and close aspects of this object, except for the final newline. - * If f_fss_complete_full, this will write any appropriate open and close aspects of this object, including the final newline. + * If f_fss_complete_none, then only the content is written. + * If f_fss_complete_next, then the content followed by any appropriate "next" character separating one content from the next, if applicable. + * If f_fss_complete_end, then the content followed by any appropriate "end" character designating the last content for some object, printing final newline, if applicable. + * If f_fss_complete_partial, this will write any appropriate open and close aspects of this content, except for the final newline. + * If f_fss_complete_full, this will write any appropriate open and close aspects of this content, including the final newline. * @param range * The start/stop location within the content string to write as an content. * @param destination diff --git a/level_1/fl_fss/c/fss_extended_list.c b/level_1/fl_fss/c/fss_extended_list.c index ec2d891..9d7e233 100644 --- a/level_1/fl_fss/c/fss_extended_list.c +++ b/level_1/fl_fss/c/fss_extended_list.c @@ -792,288 +792,394 @@ extern "C" { #endif // _di_fl_fss_extended_list_content_read_ #ifndef _di_fl_fss_extended_list_object_write_ - f_return_status fl_fss_extended_list_object_write(const f_string_static_t object, f_string_range_t *range, f_string_dynamic_t *destination) { + f_return_status fl_fss_extended_list_object_write(const f_string_static_t object, const uint8_t complete, f_string_range_t *range, f_string_dynamic_t *destination) { #ifndef _di_level_1_parameter_checking_ if (!destination) return F_status_set_error(F_parameter); #endif // _di_level_1_parameter_checking_ f_status_t status = F_none; - 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 start_buffer = 0; + fl_macro_fss_skip_past_delimit_placeholders(object, (*range)); - fl_macro_fss_skip_past_delimit_placeholders(object, (*range)) - - if (range->start > range->stop) return F_data_not_stop; - else if (range->start >= object.used) return F_data_not_eos; + if (range->start > range->stop) { + status = F_data_not_stop; + } + else if (range->start >= object.used) { + status = F_data_not_eos; + } - start_position = range->start; + if (status == F_data_not_stop || status == F_data_not_eos) { + if (complete == f_fss_complete_partial || complete == f_fss_complete_full) { + const f_status_t status_allocation = private_fl_fss_destination_increase_by(2, destination); + if (F_status_is_error(status_allocation)) return status_allocation; - // add an additional 2 to ensure that there is room for the slash delimit and the object open character. - size_allocate = destination->used + (range->stop - range->start) + 2 + f_fss_default_allocation_step; + destination->string[destination->used++] = f_fss_extended_list_open; - if (size_allocate > destination->size) { - f_macro_string_dynamic_t_resize(status, (*destination), size_allocate); + if (complete == f_fss_complete_full) { + destination->string[destination->used++] = f_fss_extended_list_open_end; + } + } - if (F_status_is_error(status)) return status; + return status; } - buffer_position.start = destination->used; - buffer_position.stop = destination->used; + // ensure that there is room for a slash delimit, the object open character, and the end of line character. + status = private_fl_fss_destination_increase_by(destination->used + (range->stop - range->start) + 3, destination); + if (F_status_is_error(status)) return status; + + const f_string_length_t input_start = range->start; + const f_string_length_t used_start = destination->used; + + f_string_length_t i = 0; + f_string_length_t slash_count = 0; + f_string_range_t range_next = f_string_range_t_initialize; + + bool ends_on_space = F_false; + + uint8_t width = 0; + + // find the first graph character. while (range->start <= range->stop && range->start < object.used) { if (object.string[range->start] == f_fss_comment) { - // comments are not allowed and this format has no way of "wrapping" a comment. - return F_status_set_error(FL_fss_found_comment); - } - else if ((status = f_fss_is_graph(object, *range)) == F_true) { + + // when a comment is found, escape it. + status = private_fl_fss_destination_increase(destination); + if (F_status_is_error(status)) break; + + destination->string[destination->used++] = f_fss_delimit_slash; break; } - else if (F_status_is_error(status)) { - return status; - } + 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 result in an invalid object, so just write the provided spaces. if (object.string[range->start] != f_fss_delimit_placeholder) { - destination->string[buffer_position.stop] = object.string[range->start]; - buffer_position.stop++; + 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; + + if (status == F_true) { + width = f_macro_utf_byte_width(object.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++] = object.string[range->start + i]; + } // for + } } status = f_utf_buffer_increment(object, range, 1); - if (F_status_is_error(status)) return status; + if (F_status_is_error(status)) break; } // while + if (F_status_is_error(status)) { + destination->used = used_start; + return status; + } + while (range->start <= range->stop && range->start < object.used) { if (object.string[range->start] == f_fss_delimit_slash) { - f_string_length_t slash_count = 1; - - destination->string[buffer_position.stop] = object.string[range->start]; - buffer_position.stop++; - - status = f_utf_buffer_increment(object, range, 1); - if (F_status_is_error(status)) return status; + slash_count = 1; - while (range->start <= range->stop && range->start < object.used) { + for (range->start++; range->start <= range->stop && range->start < object.used; range->start++) { if (object.string[range->start] == f_fss_delimit_placeholder) { - status = f_utf_buffer_increment(object, range, 1); - if (F_status_is_error(status)) return status; - continue; } else if (object.string[range->start] != f_fss_delimit_slash) { break; } - destination->string[buffer_position.stop] = object.string[range->start]; - buffer_position.stop++; - - status = f_utf_buffer_increment(object, range, 1); - if (F_status_is_error(status)) return status; - slash_count++; - } // while + } // for + + if (F_status_is_error(status)) break; if (range->start > range->stop || range->start >= object.used) { - size_allocate += slash_count; - 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; - } + // slashes at the end of the object must be delimited to avoid delimiting the object close character. + slash_count *= 2; + } - while (slash_count > 0) { - destination->string[buffer_position.stop] = f_fss_delimit_slash; - buffer_position.stop++; - slash_count--; - } // while + status = private_fl_fss_destination_increase_by(slash_count, destination); + if (F_status_is_error(status)) break; + while (slash_count--) { + destination->string[destination->used++] = f_fss_delimit_slash; + } // while + + if (range->start > range->stop || range->start >= object.used) { + ends_on_space = F_false; break; } } - else if (object.string[range->start] == f_string_eol[0]) { - if (buffer_position.stop == buffer_position.start) return F_data_not_eol; - - break; - } if (object.string[range->start] != f_fss_delimit_placeholder) { - destination->string[buffer_position.stop] = object.string[range->start]; - buffer_position.stop++; + 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; + + ends_on_space = status == F_true; + + width = f_macro_utf_byte_width(object.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++] = object.string[range->start + i]; + } // for } status = f_utf_buffer_increment(object, range, 1); - if (F_status_is_error(status)) return status; + if (F_status_is_error(status)) break; } // while - destination->string[buffer_position.stop] = f_fss_extended_list_open; - destination->string[buffer_position.stop + 1] = f_string_eol[0]; - destination->used = buffer_position.stop + 2; + if (F_status_is_error(status)) { + destination->used = used_start; + return status; + } + + if (complete == f_fss_complete_partial || complete == f_fss_complete_full) { + status = private_fl_fss_destination_increase_by(3, destination); - if (range->start > range->stop) return F_none_stop; - else if (range->start >= object.used) return F_none_eos; + if (F_status_is_error(status)) { + destination->used = used_start; + return status; + } + + if (!ends_on_space) { + destination->string[destination->used++] = f_fss_space; + } + + destination->string[destination->used++] = f_fss_extended_list_open; + + if (complete == f_fss_complete_full) { + destination->string[destination->used++] = f_fss_extended_list_open_end; + } + } + + if (range->start > range->stop) { + return F_none_stop; + } + + if (range->start >= object.used) { + return F_none_eos; + } return F_none; } #endif // _di_fl_fss_extended_list_object_write_ #ifndef _di_fl_fss_extended_list_content_write_ - f_return_status fl_fss_extended_list_content_write(const f_string_static_t content, f_string_range_t *range, f_string_dynamic_t *destination) { + f_return_status fl_fss_extended_list_content_write(const f_string_static_t content, const uint8_t complete, const f_string_static_t prepend, f_string_range_t *range, f_string_dynamic_t *destination) { #ifndef _di_level_1_parameter_checking_ + if (!range) return F_status_set_error(F_parameter); if (!destination) return F_status_set_error(F_parameter); #endif // _di_level_1_parameter_checking_ - // @todo - /* 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; - fl_macro_fss_skip_past_delimit_placeholders(content, (*range)) + fl_macro_fss_skip_past_delimit_placeholders(content, (*range)); - if (range->start > range->stop) return F_data_not_stop; - else if (range->start >= content.used) return F_data_not_eos; + if (range->start > range->stop || range->start >= content.used) { + if (complete == f_fss_complete_full || complete == f_fss_complete_end) { + status = private_fl_fss_destination_increase_by(2, destination); + if (F_status_is_error(status)) return status; - start_position = range->start; + destination->string[destination->used++] = f_fss_extended_list_close; + destination->string[destination->used++] = f_fss_extended_list_close_end; + } - // 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; + if (range->start > range->stop) { + return F_data_not_stop; + } - if (size_allocate > destination->size) { - f_macro_string_dynamic_t_resize(status, (*destination), size_allocate); - if (F_status_is_error(status)) return status; + return F_data_not_eos; } - buffer_position.start = destination->used; - buffer_position.stop = destination->used; + // ensure that there is room for a slash delimit and possibly the end of content characters. + status = private_fl_fss_destination_increase_by(destination->used + (range->stop - range->start) + 3, destination); + if (F_status_is_error(status)) return status; + + const f_string_length_t input_start = range->start; + const f_string_length_t used_start = destination->used; + + bool is_comment = F_false; + bool ends_on_eol = F_false; + bool has_graph = F_false; + bool do_prepend = F_true; + + f_string_length_t i = 0; + f_string_length_t slash_count = 0; + f_string_length_t start = 0; + + uint8_t width = 0; while (range->start <= range->stop && range->start < content.used) { if (content.string[range->start] == f_fss_delimit_slash && !is_comment) { - f_string_length_t slash_count = 1; + slash_count = 1; - destination->string[buffer_position.stop] = content.string[range->start]; - buffer_position.stop++; + if (do_prepend) { + status = private_fl_fss_destination_prepend(prepend, destination); + if (F_status_is_error(status)) break; + do_prepend = F_false; + } + + 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; + if (F_status_is_error(status)) break; - 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]; - buffer_position.stop++; - - 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_extended_list_open) { - f_string_length_t start = range->start; + start = range->start; status = f_utf_buffer_increment(content, range, 1); - if (F_status_is_error(status)) return status; + if (F_status_is_error(status)) break; while (range->start < content.used && range->start <= range->stop) { - if (content.string[range->start] == f_string_eol[0] || (status = f_fss_is_graph(content, *range)) == F_true) { + if (content.string[range->start] == f_fss_eol) { + do_prepend = F_true; break; } - if (F_status_is_error(status)) return status; + status = f_fss_is_space(content, *range); + if (F_status_is_error(status)) break; + + if (status == F_false) break; status = f_utf_buffer_increment(content, range, 1); - if (F_status_is_error(status)) return status; + if (F_status_is_error(status)) break; } // while - if (content.string[range->start] == f_string_eol[0] || range->start >= content.used || range->start > range->stop) { - size_allocate += slash_count + 1; + if (F_status_is_error(status)) break; - 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; - } + if (content.string[range->start] == f_fss_eol || range->start >= content.used || range->start > range->stop) { - while (slash_count > 0) { - destination->string[buffer_position.stop] = f_fss_delimit_slash; - buffer_position.stop++; - slash_count--; + // increase by total slashes + 1, along with the extended list open and possible newline. + status = private_fl_fss_destination_increase_by(slash_count + 3, destination); + if (F_status_is_error(status)) break; + + while (slash_count--) { + destination->string[destination->used++] = f_fss_delimit_slash; } // while - destination->string[buffer_position.stop] = f_fss_delimit_slash; - buffer_position.stop++; + 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)) break; + } + + destination->string[destination->used++] = f_fss_extended_list_open; + + if (content.string[range->start] == f_fss_eol) { + destination->string[destination->used++] = f_fss_eol; + ends_on_eol = F_true; + } + else { + ends_on_eol = F_false; + } - destination->string[buffer_position.stop] = f_fss_extended_list_open; - buffer_position.stop++; range->start = start + 1; continue; } } else if (content.string[range->start] == f_fss_extended_list_open && !is_comment) { - f_string_length_t 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] || (status = f_fss_is_graph(content, *range)) == F_true) { - break; - } + if (content.string[range->start] == f_fss_eol) break; - if (F_status_is_error(status)) return status; + status = f_fss_is_space(content, *range); + if (F_status_is_error(status)) break; + + if (status == F_false) break; status = f_utf_buffer_increment(content, range, 1); - if (F_status_is_error(status)) return status; + if (F_status_is_error(status)) break; } // while - if (content.string[range->start] == f_string_eol[0] || range->start >= content.used || range->start > range->stop) { - size_allocate++; + if (F_status_is_error(status)) break; - if (size_allocate > destination->size) { - f_macro_string_dynamic_t_resize(status, (*destination), size_allocate + f_fss_default_allocation_step); + if (do_prepend) { + status = private_fl_fss_destination_prepend(prepend, destination); + if (F_status_is_error(status)) break; - if (F_status_is_error(status)) return status; + do_prepend = F_false; + } + + if (content.string[range->start] == f_fss_eol || range->start >= content.used || range->start > range->stop) { + if (content.string[range->start] == f_fss_eol) { + do_prepend = F_true; } - destination->string[buffer_position.stop] = f_fss_delimit_slash; - buffer_position.stop++; + // increase by slash and extended list open and possible newline. + status = private_fl_fss_destination_increase_by(3, destination); + if (F_status_is_error(status)) break; + + 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)) break; + } + + destination->string[destination->used++] = f_fss_extended_list_open; + + if (content.string[range->start] == f_fss_eol) { + destination->string[destination->used++] = f_fss_eol; + ends_on_eol = F_true; + } + else { + ends_on_eol = F_false; + } - destination->string[buffer_position.stop] = f_fss_extended_list_open; - buffer_position.stop++; 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; } @@ -1081,24 +1187,63 @@ extern "C" { has_graph = F_true; } else if (F_status_is_error(status)) { - return status; + break; } if (content.string[range->start] != f_fss_delimit_placeholder) { - destination->string[buffer_position.stop] = content.string[range->start]; - buffer_position.stop++; + if (do_prepend) { + status = private_fl_fss_destination_prepend(prepend, destination); + if (F_status_is_error(status)) break; + + do_prepend = F_false; + } + + if (content.string[range->start] == f_fss_eol) { + do_prepend = F_true; + ends_on_eol = F_true; + } + else { + ends_on_eol = F_false; + } + + 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; + if (F_status_is_error(status)) break; } // while - destination->string[buffer_position.stop] = f_string_eol[0]; - destination->used = buffer_position.stop + 1; + if (F_status_is_error(status)) { + destination->used = used_start; + return status; + } - if (range->start > range->stop) return F_none_stop; - else if (range->start >= content.used) return F_none_eos; - */ + if (complete == f_fss_complete_full || complete == f_fss_complete_end) { + status = private_fl_fss_destination_increase_by(3, destination); + if (F_status_is_error(status)) return status; + + if (!ends_on_eol) { + destination->string[destination->used++] = f_fss_eol; + } + + destination->string[destination->used++] = f_fss_extended_list_close; + destination->string[destination->used++] = f_fss_extended_list_close_end; + } + + if (range->start > range->stop) { + return F_none_stop; + } + + if (range->start >= content.used) { + return F_none_eos; + } return F_none; } diff --git a/level_1/fl_fss/c/fss_extended_list.h b/level_1/fl_fss/c/fss_extended_list.h index 8f5c740..e40cdfa 100644 --- a/level_1/fl_fss/c/fss_extended_list.h +++ b/level_1/fl_fss/c/fss_extended_list.h @@ -133,6 +133,10 @@ extern "C" { * * @param object * The string to write as (does not stop at NULLS, they are ignored and not written). + * @param complete + * If f_fss_complete_none, then only the object name is written. + * If f_fss_complete_partial, this will write any appropriate open and close aspects of this object. + * If f_fss_complete_full, this will write any appropriate open and close aspects of this object. * @param range * The start/stop location within the object string to write as an object. * @param destination @@ -146,13 +150,14 @@ extern "C" { * F_none_stop on success after reaching stopping point . * F_incomplete_utf (with error bit) is returned on failure to read/process a UTF-8 character due to the character being potentially incomplete. * F_memory_reallocation (with error bit) on reallocation error. + * F_none_eol (with error bit) after reaching an EOL, which is not supported by the standard. * F_parameter (with error bit) if a parameter is invalid. * F_utf (with error bit) is returned on failure to read/process a UTF-8 character. * * Errors (with error bit) from: f_utf_buffer_increment(). */ #ifndef _di_fl_fss_extended_list_object_write_ - extern f_return_status fl_fss_extended_list_object_write(const f_string_static_t object, f_string_range_t *range, f_string_dynamic_t *destination); + extern f_return_status fl_fss_extended_list_object_write(const f_string_static_t object, const uint8_t complete, f_string_range_t *range, f_string_dynamic_t *destination); #endif // _di_fl_fss_extended_list_object_write_ /** @@ -165,6 +170,16 @@ extern "C" { * * @param content * The string to write as (does not stop at NULLS, they are ignored and not written). + * @param complete + * If f_fss_complete_none, then only the content is written. + * If f_fss_complete_next, then the content followed by any appropriate "next" character separating one content from the next, if applicable. + * If f_fss_complete_end, then the content followed by any appropriate "end" character designating the last content for some object, printing final newline, if applicable. + * If f_fss_complete_partial, this will write any appropriate open and close aspects of this content, except for the final newline. + * If f_fss_complete_full, this will write any appropriate open and close aspects of this content, including the final newline. + * @param prepend + * A string of whitespace to prepend at the start of each line. + * This should only be whitespace, anything else could product invalid content. + * Set prepend.used to 0 to not use. * @param range * The start/stop location within the content string to write as an content. * @param destination @@ -184,7 +199,7 @@ extern "C" { * Errors (with error bit) from: f_utf_buffer_increment(). */ #ifndef _di_fl_fss_extended_list_content_write_ - extern f_return_status fl_fss_extended_list_content_write(const f_string_static_t content, f_string_range_t *range, f_string_dynamic_t *destination); + extern f_return_status fl_fss_extended_list_content_write(const f_string_static_t content, const uint8_t complete, const f_string_static_t prepend, f_string_range_t *range, f_string_dynamic_t *destination); #endif // _di_fl_fss_extended_list_content_write_ #ifdef __cplusplus diff --git a/level_1/fl_fss/c/private-fss.c b/level_1/fl_fss/c/private-fss.c index a6fc861..b3b1700 100644 --- a/level_1/fl_fss/c/private-fss.c +++ b/level_1/fl_fss/c/private-fss.c @@ -838,7 +838,7 @@ extern "C" { } #endif // !defined(_di_fl_fss_basic_object_write_) || !defined(_di_fl_fss_extended_object_write_) || !defined(_di_fl_fss_extended_content_write_) -#if !defined(_di_fl_fss_basic_object_write_) || !defined(_di_fl_fss_basic_content_write_) || !defined(_di_fl_fss_basic_list_object_write_) || !defined(_di_fl_fss_extended_object_write_) || !defined(_di_fl_fss_extended_content_write_) +#if !defined(_di_fl_fss_basic_object_write_) || !defined(_di_fl_fss_basic_content_write_) || !defined(_di_fl_fss_basic_list_object_write_) || !defined(_di_fl_fss_basic_list_content_write_) || !defined(_di_fl_fss_extended_object_write_) || !defined(_di_fl_fss_extended_content_write_) || !defined(_di_fl_fss_extended_list_object_write_) || !defined(_di_fl_fss_extended_list_content_write_) f_return_status private_fl_fss_destination_increase(f_string_dynamic_t *destination) { f_status_t status = F_none; @@ -857,9 +857,9 @@ extern "C" { return status; } -#endif // !defined(_di_fl_fss_basic_object_write_) || !defined(_di_fl_fss_basic_content_write_) || !defined(_di_fl_fss_basic_list_object_write_) || !defined(_di_fl_fss_extended_object_write_) || !defined(_di_fl_fss_extended_content_write_) +#endif // !defined(_di_fl_fss_basic_object_write_) || !defined(_di_fl_fss_basic_content_write_) || !defined(_di_fl_fss_basic_list_object_write_) || !defined(_di_fl_fss_basic_list_content_write_) || !defined(_di_fl_fss_extended_object_write_) || !defined(_di_fl_fss_extended_content_write_) || !defined(_di_fl_fss_extended_list_object_write_) || !defined(_di_fl_fss_extended_list_content_write_) -#if !defined(_di_fl_fss_basic_object_write_) || !defined(_di_fl_fss_basic_content_write_) || !defined(_di_fl_fss_basic_list_object_write_) || !defined(_di_fl_fss_extended_object_write_) || !defined(_di_fl_fss_extended_content_write_) +#if !defined(_di_fl_fss_basic_object_write_) || !defined(_di_fl_fss_basic_content_write_) || !defined(_di_fl_fss_basic_list_object_write_) || !defined(_di_fl_fss_basic_list_content_write_) || !defined(_di_fl_fss_extended_object_write_) || !defined(_di_fl_fss_extended_content_write_) || !defined(_di_fl_fss_extended_list_object_write_) || !defined(_di_fl_fss_extended_list_content_write_) f_return_status private_fl_fss_destination_increase_by(const f_string_length_t amount, f_string_dynamic_t *destination) { f_status_t status = F_none; @@ -873,7 +873,27 @@ extern "C" { return status; } -#endif // !defined(_di_fl_fss_basic_object_write_) || !defined(_di_fl_fss_basic_content_write_) || !defined(_di_fl_fss_basic_list_object_write_) || !defined(_di_fl_fss_extended_object_write_) || !defined(_di_fl_fss_extended_content_write_) +#endif // !defined(_di_fl_fss_basic_object_write_) || !defined(_di_fl_fss_basic_content_write_) || !defined(_di_fl_fss_basic_list_object_write_) || !defined(_di_fl_fss_basic_list_content_write_) || !defined(_di_fl_fss_extended_object_write_) || !defined(_di_fl_fss_extended_content_write_) || !defined(_di_fl_fss_extended_list_object_write_) || !defined(_di_fl_fss_extended_list_content_write_) + +#if !defined(_di_fl_fss_basic_list_content_write_) || !defined(_di_fl_fss_extended_list_content_write_) + f_return_status private_fl_fss_destination_prepend(const f_string_static_t prepend, f_string_dynamic_t *destination) { + + if (!prepend.used) { + return F_none; + } + + if (prepend.used) { + f_status_t status = private_fl_fss_destination_increase_by(prepend.used, destination); + if (F_status_is_error(status)) return status; + } + + for (f_string_length_t i = 0; i < prepend.used; i++) { + destination->string[destination->used++] = prepend.string[i]; + } // for + + return F_none; + } +#endif // !defined(_di_fl_fss_basic_list_content_write_) || !defined(_di_fl_fss_extended_list_content_write_) #ifdef __cplusplus } // extern "C" diff --git a/level_1/fl_fss/c/private-fss.h b/level_1/fl_fss/c/private-fss.h index b42c3ca..1b4fe2e 100644 --- a/level_1/fl_fss/c/private-fss.h +++ b/level_1/fl_fss/c/private-fss.h @@ -132,12 +132,15 @@ extern "C" { * @see fl_fss_basic_object_write() * @see fl_fss_basic_content_write() * @see fl_fss_basic_list_object_write() + * @see fl_fss_basic_list_content_write() * @see fl_fss_extended_object_write() * @see fl_fss_extended_content_write() + * @see fl_fss_extended_list_object_write() + * @see fl_fss_extended_list_content_write() */ -#if !defined(_di_fl_fss_basic_object_write_) || !defined(_di_fl_fss_basic_content_write_) || !defined(_di_fl_fss_basic_list_object_write_) || !defined(_di_fl_fss_extended_object_write_) || !defined(_di_fl_fss_extended_content_write_) +#if !defined(_di_fl_fss_basic_object_write_) || !defined(_di_fl_fss_basic_content_write_) || !defined(_di_fl_fss_basic_list_object_write_) || !defined(_di_fl_fss_basic_list_content_write_) || !defined(_di_fl_fss_extended_object_write_) || !defined(_di_fl_fss_extended_content_write_) || !defined(_di_fl_fss_extended_list_object_write_) || !defined(_di_fl_fss_extended_list_content_write_) extern f_return_status private_fl_fss_destination_increase(f_string_dynamic_t *destination) f_gcc_attribute_visibility_internal; -#endif // !defined(_di_fl_fss_basic_object_write_) || !defined(_di_fl_fss_basic_content_write_) || !defined(_di_fl_fss_basic_list_object_write_) || !defined(_di_fl_fss_extended_object_write_) || !defined(_di_fl_fss_extended_content_write_) +#endif // !defined(_di_fl_fss_basic_object_write_) || !defined(_di_fl_fss_basic_content_write_) || !defined(_di_fl_fss_basic_list_object_write_) || !defined(_di_fl_fss_basic_list_content_write_) || !defined(_di_fl_fss_extended_object_write_) || !defined(_di_fl_fss_extended_content_write_) || !defined(_di_fl_fss_extended_list_object_write_) || !defined(_di_fl_fss_extended_list_content_write_) /** * Increase the size of destination buffer by the given amount, but only if necessary. @@ -155,12 +158,36 @@ extern "C" { * @see fl_fss_basic_object_write() * @see fl_fss_basic_content_write() * @see fl_fss_basic_list_object_write() + * @see fl_fss_basic_list_content_write() * @see fl_fss_extended_object_write() * @see fl_fss_extended_content_write() + * @see fl_fss_extended_list_object_write() + * @see fl_fss_extended_list_content_write() */ -#if !defined(_di_fl_fss_basic_object_write_) || !defined(_di_fl_fss_basic_content_write_) || !defined(_di_fl_fss_basic_list_object_write_) || !defined(_di_fl_fss_extended_object_write_) || !defined(_di_fl_fss_extended_content_write_) - f_return_status private_fl_fss_destination_increase_by(const f_string_length_t amount, f_string_dynamic_t *destination); -#endif // !defined(_di_fl_fss_basic_object_write_) || !defined(_di_fl_fss_basic_content_write_) || !defined(_di_fl_fss_basic_list_object_write_) || !defined(_di_fl_fss_extended_object_write_) || !defined(_di_fl_fss_extended_content_write_) +#if !defined(_di_fl_fss_basic_object_write_) || !defined(_di_fl_fss_basic_content_write_) || !defined(_di_fl_fss_basic_list_object_write_) || !defined(_di_fl_fss_basic_list_content_write_) || !defined(_di_fl_fss_extended_object_write_) || !defined(_di_fl_fss_extended_content_write_) || !defined(_di_fl_fss_extended_list_object_write_) || !defined(_di_fl_fss_extended_list_content_write_) + f_return_status private_fl_fss_destination_increase_by(const f_string_length_t amount, f_string_dynamic_t *destination) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_fl_fss_basic_object_write_) || !defined(_di_fl_fss_basic_content_write_) || !defined(_di_fl_fss_basic_list_object_write_) || !defined(_di_fl_fss_basic_list_content_write_) || !defined(_di_fl_fss_extended_object_write_) || !defined(_di_fl_fss_extended_content_write_) || !defined(_di_fl_fss_extended_list_object_write_) || !defined(_di_fl_fss_extended_list_content_write_) + +/** + * Prepend the given string onto the destination buffer, allocating space as necessary + * + * @param prepend + * A string to prepend at the start of each line, such as spaces. + * Set prepend.used to 0 to not use. + * @param destination + * The destination buffer to prepend to. + * + * @return + * F_none on success. + * F_memory_reallocation (with error bit) on reallocation error. + * F_string_too_large (with error bit) if appended string length is too large to store in the destination. + * + * @see fl_fss_basic_list_content_write() + * @see fl_fss_extended_list_content_write() + */ +#if !defined(_di_fl_fss_basic_list_content_write_) || !defined(_di_fl_fss_extended_list_content_write_) + f_return_status private_fl_fss_destination_prepend(const f_string_static_t prepend, f_string_dynamic_t *destination) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_fl_fss_basic_list_content_write_) || !defined(_di_fl_fss_extended_list_content_write_) #ifdef __cplusplus } // extern "C" diff --git a/level_2/fll_fss/c/fss_basic_list.c b/level_2/fll_fss/c/fss_basic_list.c index f40e33f..fbce3c8 100644 --- a/level_2/fll_fss/c/fss_basic_list.c +++ b/level_2/fll_fss/c/fss_basic_list.c @@ -131,7 +131,7 @@ extern "C" { #endif // _di_fll_fss_basic_list_read_ #ifndef _di_fll_fss_basic_list_write_ - f_return_status fll_fss_basic_list_write(const f_string_static_t object, const f_string_statics_t contents, f_string_dynamic_t *destination) { + f_return_status fll_fss_basic_list_write(const f_string_static_t object, const f_string_statics_t contents, const f_string_static_t contents_prepend, f_string_dynamic_t *destination) { #ifndef _di_level_2_parameter_checking_ if (!destination) return F_status_set_error(F_parameter); #endif // _di_level_2_parameter_checking_ @@ -150,7 +150,7 @@ extern "C" { range.start = 0; range.stop = contents.array[0].used - 1; - status = fl_fss_basic_list_content_write(contents.array[0], &range, destination); + status = fl_fss_basic_list_content_write(contents.array[0], f_fss_complete_full, contents_prepend, &range, destination); } } diff --git a/level_2/fll_fss/c/fss_basic_list.h b/level_2/fll_fss/c/fss_basic_list.h index 7e600b8..9e44850 100644 --- a/level_2/fll_fss/c/fss_basic_list.h +++ b/level_2/fll_fss/c/fss_basic_list.h @@ -67,6 +67,9 @@ extern "C" { * A string representing the object. * @param contents * An array of strings representing multiple content to write. + * @param contents_prepend + * A string to prepend at the start of each line in contents, such as spaces. + * Set prepend.used to 0 to not use. * @param buffer * The buffer to write to. * @@ -86,7 +89,7 @@ extern "C" { * Errors (with error bit) from: fl_string_dynamic_size_increase(). */ #ifndef _di_fll_fss_basic_list_write_ - extern f_return_status fll_fss_basic_list_write(const f_string_static_t object, const f_string_statics_t contents, f_string_dynamic_t *buffer); + extern f_return_status fll_fss_basic_list_write(const f_string_static_t object, const f_string_statics_t contents, const f_string_static_t contents_prepend, f_string_dynamic_t *buffer); #endif // _di_fll_fss_basic_list_write_ #ifdef __cplusplus diff --git a/level_3/fss_basic_list_write/c/fss_basic_list_write.c b/level_3/fss_basic_list_write/c/fss_basic_list_write.c index 07c6bc1..babfe96 100644 --- a/level_3/fss_basic_list_write/c/fss_basic_list_write.c +++ b/level_3/fss_basic_list_write/c/fss_basic_list_write.c @@ -23,10 +23,11 @@ extern "C" { printf("%c", f_string_eol[0]); fll_program_print_help_option(file, context, fss_basic_list_write_short_file, fss_basic_list_write_long_file, f_console_symbol_short_enable, f_console_symbol_long_enable, " Specify a file to send output to."); - fll_program_print_help_option(file, context, fss_basic_list_write_short_content, fss_basic_list_write_long_content, f_console_symbol_short_enable, f_console_symbol_long_enable, "The content to output."); + fll_program_print_help_option(file, context, fss_basic_list_write_short_content, fss_basic_list_write_long_content, f_console_symbol_short_enable, f_console_symbol_long_enable, "The Content to output."); fll_program_print_help_option(file, context, fss_basic_list_write_short_double, fss_basic_list_write_long_double, f_console_symbol_short_enable, f_console_symbol_long_enable, " Use double quotes (default)."); - fll_program_print_help_option(file, context, fss_basic_list_write_short_object, fss_basic_list_write_long_object, f_console_symbol_short_enable, f_console_symbol_long_enable, " The object to output."); - fll_program_print_help_option(file, context, fss_basic_list_write_short_partial, fss_basic_list_write_long_partial, f_console_symbol_short_enable, f_console_symbol_long_enable, "Do not output end of object/content character."); + fll_program_print_help_option(file, context, fss_basic_list_write_short_object, fss_basic_list_write_long_object, f_console_symbol_short_enable, f_console_symbol_long_enable, " The Object to output."); + fll_program_print_help_option(file, context, fss_basic_list_write_short_partial, fss_basic_list_write_long_partial, f_console_symbol_short_enable, f_console_symbol_long_enable, "Do not output end of Object/Content character."); + fll_program_print_help_option(file, context, fss_basic_list_write_short_prepend, fss_basic_list_write_long_prepend, f_console_symbol_short_enable, f_console_symbol_long_enable, "Prepend the given whitespace characters to the start of each multi-line Content."); fll_program_print_help_option(file, context, fss_basic_list_write_short_single, fss_basic_list_write_long_single, f_console_symbol_short_enable, f_console_symbol_long_enable, " Use single quotes."); fll_program_print_help_usage(file, context, fss_basic_list_write_name, ""); @@ -267,6 +268,59 @@ extern "C" { } } + if (F_status_is_error_not(status)) { + if (data->parameters[fss_basic_list_write_parameter_prepend].result == f_console_result_found) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data->error.to.stream, data->context.set.error, "%sThe parameter '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_basic_list_write_long_prepend); + fl_color_print(data->error.to.stream, data->context.set.error, "' was specified, but no value was given.%c", f_string_eol[0]); + } + + status = F_status_set_error(F_parameter); + } + else if (data->parameters[fss_basic_list_write_parameter_prepend].result == f_console_result_additional) { + const f_string_length_t index = data->parameters[fss_basic_list_write_parameter_prepend].additional.array[data->parameters[fss_basic_list_write_parameter_prepend].additional.used - 1]; + const f_string_length_t length = strnlen(arguments.argv[index], f_console_length_size); + + if (length) { + f_string_range_t range = f_macro_string_range_t_initialize(length); + + data->prepend.string = arguments.argv[index]; + data->prepend.used = length; + data->prepend.size = length; + + for (; range.start < length; range.start++) { + + status = f_fss_is_space(data->prepend, range); + if (F_status_is_error(status)) break; + + if (status == F_false) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data->error.to.stream, data->context.set.error, "%sThe value for the parameter '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_basic_list_write_long_prepend); + fl_color_print(data->error.to.stream, data->context.set.error, "' must only contain whitespace.%c", f_string_eol[0]); + } + + status = F_status_set_error(F_parameter); + break; + } + } // for + } + else { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data->error.to.stream, data->context.set.error, "%sThe value for the parameter '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_basic_list_write_long_prepend); + fl_color_print(data->error.to.stream, data->context.set.error, "' must not be an empty string.%c", f_string_eol[0]); + } + + status = F_status_set_error(F_parameter); + } + } + } + f_fss_quote_t quote = f_fss_delimit_quote_double; if (F_status_is_error_not(status)) { diff --git a/level_3/fss_basic_list_write/c/fss_basic_list_write.h b/level_3/fss_basic_list_write/c/fss_basic_list_write.h index 092d5f3..cbde9f7 100644 --- a/level_3/fss_basic_list_write/c/fss_basic_list_write.h +++ b/level_3/fss_basic_list_write/c/fss_basic_list_write.h @@ -62,6 +62,7 @@ extern "C" { #define fss_basic_list_write_short_double "d" #define fss_basic_list_write_short_object "o" #define fss_basic_list_write_short_partial "p" + #define fss_basic_list_write_short_prepend "P" #define fss_basic_list_write_short_single "s" #define fss_basic_list_write_long_file "file" @@ -69,6 +70,7 @@ extern "C" { #define fss_basic_list_write_long_double "double" #define fss_basic_list_write_long_object "object" #define fss_basic_list_write_long_partial "partial" + #define fss_basic_list_write_long_prepend "prepend" #define fss_basic_list_write_long_single "single" enum { @@ -87,6 +89,7 @@ extern "C" { fss_basic_list_write_parameter_double, fss_basic_list_write_parameter_object, fss_basic_list_write_parameter_partial, + fss_basic_list_write_parameter_prepend, fss_basic_list_write_parameter_single, }; @@ -106,10 +109,11 @@ extern "C" { f_console_parameter_t_initialize(fss_basic_list_write_short_double, fss_basic_list_write_long_double, 0, 0, f_console_type_normal), \ f_console_parameter_t_initialize(fss_basic_list_write_short_object, fss_basic_list_write_long_object, 0, 1, f_console_type_normal), \ f_console_parameter_t_initialize(fss_basic_list_write_short_partial, fss_basic_list_write_long_partial, 0, 0, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_basic_list_write_short_prepend, fss_basic_list_write_long_prepend, 0, 1, f_console_type_normal), \ f_console_parameter_t_initialize(fss_basic_list_write_short_single, fss_basic_list_write_long_single, 0, 0, f_console_type_normal), \ } - #define fss_basic_list_write_total_parameters 15 + #define fss_basic_list_write_total_parameters 16 #endif // _di_fss_basic_list_write_defines_ #ifndef _di_fss_basic_list_write_data_t_ @@ -121,6 +125,7 @@ extern "C" { f_file_t output; fll_error_print_t error; + f_string_static_t prepend; f_color_context_t context; } fss_basic_list_write_data_t; @@ -132,6 +137,7 @@ extern "C" { F_false, \ f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \ fll_error_print_t_initialize, \ + f_string_static_t_initialize, \ f_color_context_t_initialize, \ } #endif // _di_fss_basic_list_write_data_t_ 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 564831a..4936980 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 @@ -67,7 +67,7 @@ extern "C" { range.stop = 0; } - status = fl_fss_basic_list_object_write(*object, content ? f_fss_complete_full : f_fss_complete_partial, &range, buffer); + status = fl_fss_basic_list_object_write(*object, content ? f_fss_complete_full : f_fss_complete_none, &range, buffer); if (F_status_set_fine(status) == F_none_eol) { fss_basic_list_write_error_parameter_unsupported_eol_print(data); @@ -85,7 +85,7 @@ extern "C" { range.start = 0; range.stop = content->used - 1; - status = fl_fss_basic_list_content_write(*content, &range, buffer); + status = fl_fss_basic_list_content_write(*content, object ? f_fss_complete_full : f_fss_complete_none, data.prepend, &range, buffer); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "fl_fss_basic_list_content_write", F_true); @@ -93,6 +93,15 @@ extern "C" { } } + if (!object || !content) { + status = fl_string_append(f_string_eol, 1, buffer); + + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "fl_string_append", F_true); + return status; + } + } + f_print_dynamic(output.stream, *buffer); buffer->used = 0; diff --git a/level_3/fss_basic_write/c/fss_basic_write.c b/level_3/fss_basic_write/c/fss_basic_write.c index 0f71d44..8e34bf5 100644 --- a/level_3/fss_basic_write/c/fss_basic_write.c +++ b/level_3/fss_basic_write/c/fss_basic_write.c @@ -23,10 +23,11 @@ extern "C" { printf("%c", f_string_eol[0]); fll_program_print_help_option(file, context, fss_basic_write_short_file, fss_basic_write_long_file, f_console_symbol_short_enable, f_console_symbol_long_enable, " Specify a file to send output to."); - fll_program_print_help_option(file, context, fss_basic_write_short_content, fss_basic_write_long_content, f_console_symbol_short_enable, f_console_symbol_long_enable, "The content to output."); + fll_program_print_help_option(file, context, fss_basic_write_short_content, fss_basic_write_long_content, f_console_symbol_short_enable, f_console_symbol_long_enable, "The Content to output."); fll_program_print_help_option(file, context, fss_basic_write_short_double, fss_basic_write_long_double, f_console_symbol_short_enable, f_console_symbol_long_enable, " Use double quotes (default)."); - fll_program_print_help_option(file, context, fss_basic_write_short_object, fss_basic_write_long_object, f_console_symbol_short_enable, f_console_symbol_long_enable, " The object to output."); - fll_program_print_help_option(file, context, fss_basic_write_short_partial, fss_basic_write_long_partial, f_console_symbol_short_enable, f_console_symbol_long_enable, "Do not output end of object/content character."); + fll_program_print_help_option(file, context, fss_basic_write_short_object, fss_basic_write_long_object, f_console_symbol_short_enable, f_console_symbol_long_enable, " The Object to output."); + fll_program_print_help_option(file, context, fss_basic_write_short_partial, fss_basic_write_long_partial, f_console_symbol_short_enable, f_console_symbol_long_enable, "Do not output end of Object/Content character."); + fll_program_print_help_option(file, context, fss_basic_write_short_prepend, fss_basic_write_long_prepend, f_console_symbol_short_enable, f_console_symbol_long_enable, "Prepend the given whitespace characters to the start of each multi-line Content."); fll_program_print_help_option(file, context, fss_basic_write_short_single, fss_basic_write_long_single, f_console_symbol_short_enable, f_console_symbol_long_enable, " Use single quotes."); fll_program_print_help_usage(file, context, fss_basic_write_name, ""); @@ -53,6 +54,12 @@ extern "C" { printf("%c", f_string_eol[0]); + printf(" The FSS-0000 (Basic) specification does not support multi-line Content, therefore the parameter '"); + fl_color_print(f_type_output, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_basic_write_long_prepend); + printf("' does nothing.%c", f_string_eol[0]); + + printf("%c", f_string_eol[0]); + return F_none; } #endif // _di_fss_basic_write_print_help_ @@ -259,6 +266,57 @@ extern "C" { } } + if (F_status_is_error_not(status)) { + if (data->parameters[fss_basic_write_parameter_prepend].result == f_console_result_found) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data->error.to.stream, data->context.set.error, "%sThe parameter '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_basic_write_long_prepend); + fl_color_print(data->error.to.stream, data->context.set.error, "' was specified, but no value was given.%c", f_string_eol[0]); + } + + status = F_status_set_error(F_parameter); + } + else if (data->parameters[fss_basic_write_parameter_prepend].result == f_console_result_additional) { + const f_string_length_t index = data->parameters[fss_basic_write_parameter_prepend].additional.array[data->parameters[fss_basic_write_parameter_prepend].additional.used - 1]; + const f_string_length_t length = strnlen(arguments.argv[index], f_console_length_size); + + // Even though this standard does not utilize this parameter, provide the validation for consistency. + if (length) { + f_string_range_t range = f_macro_string_range_t_initialize(length); + const f_string_static_t prepend = f_macro_string_static_t_initialize(arguments.argv[index], length); + + for (; range.start < length; range.start++) { + + status = f_fss_is_space(prepend, range); + if (F_status_is_error(status)) break; + + if (status == F_false) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data->error.to.stream, data->context.set.error, "%sThe value for the parameter '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_basic_write_long_prepend); + fl_color_print(data->error.to.stream, data->context.set.error, "' must only contain whitespace.%c", f_string_eol[0]); + } + + status = F_status_set_error(F_parameter); + break; + } + } // for + } + else { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data->error.to.stream, data->context.set.error, "%sThe value for the parameter '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_basic_write_long_prepend); + fl_color_print(data->error.to.stream, data->context.set.error, "' must not be an empty string.%c", f_string_eol[0]); + } + + status = F_status_set_error(F_parameter); + } + } + } + f_fss_quote_t quote = f_fss_delimit_quote_double; if (F_status_is_error_not(status)) { diff --git a/level_3/fss_basic_write/c/fss_basic_write.h b/level_3/fss_basic_write/c/fss_basic_write.h index ce3e0c0..e56c7e5 100644 --- a/level_3/fss_basic_write/c/fss_basic_write.h +++ b/level_3/fss_basic_write/c/fss_basic_write.h @@ -63,6 +63,7 @@ extern "C" { #define fss_basic_write_short_double "d" #define fss_basic_write_short_object "o" #define fss_basic_write_short_partial "p" + #define fss_basic_write_short_prepend "P" #define fss_basic_write_short_single "s" #define fss_basic_write_long_file "file" @@ -70,6 +71,7 @@ extern "C" { #define fss_basic_write_long_double "double" #define fss_basic_write_long_object "object" #define fss_basic_write_long_partial "partial" + #define fss_basic_write_long_prepend "prepend" #define fss_basic_write_long_single "single" enum { @@ -88,6 +90,7 @@ extern "C" { fss_basic_write_parameter_double, fss_basic_write_parameter_object, fss_basic_write_parameter_partial, + fss_basic_write_parameter_prepend, fss_basic_write_parameter_single, }; @@ -107,10 +110,11 @@ extern "C" { f_console_parameter_t_initialize(fss_basic_write_short_double, fss_basic_write_long_double, 0, 0, f_console_type_normal), \ f_console_parameter_t_initialize(fss_basic_write_short_object, fss_basic_write_long_object, 0, 1, f_console_type_normal), \ f_console_parameter_t_initialize(fss_basic_write_short_partial, fss_basic_write_long_partial, 0, 0, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_basic_write_short_prepend, fss_basic_write_long_prepend, 0, 1, f_console_type_normal), \ f_console_parameter_t_initialize(fss_basic_write_short_single, fss_basic_write_long_single, 0, 0, f_console_type_normal), \ } - #define fss_basic_write_total_parameters 15 + #define fss_basic_write_total_parameters 16 #endif // _di_fss_basic_write_defines_ #ifndef _di_fss_basic_write_data_ diff --git a/level_3/fss_basic_write/c/private-fss_basic_write.c b/level_3/fss_basic_write/c/private-fss_basic_write.c index 6005c6f..06a3213 100644 --- a/level_3/fss_basic_write/c/private-fss_basic_write.c +++ b/level_3/fss_basic_write/c/private-fss_basic_write.c @@ -67,7 +67,7 @@ extern "C" { range.stop = 0; } - status = fl_fss_basic_object_write(*object, quote, content ? f_fss_complete_full : f_fss_complete_partial, &range, buffer); + status = fl_fss_basic_object_write(*object, quote, content ? f_fss_complete_full : f_fss_complete_none, &range, buffer); if (F_status_set_fine(status) == F_none_eol) { fss_basic_write_error_parameter_unsupported_eol_print(data); @@ -91,7 +91,7 @@ extern "C" { range.stop = 0; } - status = fl_fss_basic_content_write(*content, object ? f_fss_complete_full : f_fss_complete_partial, &range, buffer); + status = fl_fss_basic_content_write(*content, object ? f_fss_complete_full : f_fss_complete_none, &range, buffer); if (F_status_set_fine(status) == F_none_eol) { fss_basic_write_error_parameter_unsupported_eol_print(data); @@ -104,8 +104,8 @@ extern "C" { return status; } } - else { - // objects in this standard do not have EOL, so add an EOL for printing purposes when there is no desired content. + + if (!object || !content) { status = fl_string_append(f_string_eol, 1, buffer); if (F_status_is_error(status)) { diff --git a/level_3/fss_extended_list_write/c/fss_extended_list_write.c b/level_3/fss_extended_list_write/c/fss_extended_list_write.c new file mode 100644 index 0000000..f4fef5d --- /dev/null +++ b/level_3/fss_extended_list_write/c/fss_extended_list_write.c @@ -0,0 +1,467 @@ +#include "fss_extended_list_write.h" +#include "private-fss_extended_list_write.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fss_extended_list_write_print_help_ + f_return_status fss_extended_list_write_print_help(const f_file_t file, const f_color_context_t context) { + + fll_program_print_help_header(file, context, fss_extended_list_write_name_long, fss_extended_list_write_version); + + fll_program_print_help_option(file, context, f_console_standard_short_help, f_console_standard_long_help, f_console_symbol_short_enable, f_console_symbol_long_enable, " Print this help message."); + fll_program_print_help_option(file, context, f_console_standard_short_dark, f_console_standard_long_dark, f_console_symbol_short_disable, f_console_symbol_long_disable, " Output using colors that show up better on dark backgrounds."); + fll_program_print_help_option(file, context, f_console_standard_short_light, f_console_standard_long_light, f_console_symbol_short_disable, f_console_symbol_long_disable, " Output using colors that show up better on light backgrounds."); + fll_program_print_help_option(file, context, f_console_standard_short_no_color, f_console_standard_long_no_color, f_console_symbol_short_disable, f_console_symbol_long_disable, "Do not output in color."); + fll_program_print_help_option(file, context, f_console_standard_short_quiet, f_console_standard_long_quiet, f_console_symbol_short_disable, f_console_symbol_long_disable, " Decrease verbosity beyond normal output."); + fll_program_print_help_option(file, context, f_console_standard_short_normal, f_console_standard_long_normal, f_console_symbol_short_disable, f_console_symbol_long_disable, " Set verbosity to normal output."); + fll_program_print_help_option(file, context, f_console_standard_short_verbose, f_console_standard_long_verbose, f_console_symbol_short_disable, f_console_symbol_long_disable, " Increase verbosity beyond normal output."); + fll_program_print_help_option(file, context, f_console_standard_short_debug, f_console_standard_long_debug, f_console_symbol_short_disable, f_console_symbol_long_disable, " Enable debugging, inceasing verbosity beyond normal output."); + fll_program_print_help_option(file, context, f_console_standard_short_version, f_console_standard_long_version, f_console_symbol_short_disable, f_console_symbol_long_disable, " Print only the version number."); + + printf("%c", f_string_eol[0]); + + fll_program_print_help_option(file, context, fss_extended_list_write_short_file, fss_extended_list_write_long_file, f_console_symbol_short_enable, f_console_symbol_long_enable, " Specify a file to send output to."); + fll_program_print_help_option(file, context, fss_extended_list_write_short_content, fss_extended_list_write_long_content, f_console_symbol_short_enable, f_console_symbol_long_enable, "The Content to output."); + fll_program_print_help_option(file, context, fss_extended_list_write_short_double, fss_extended_list_write_long_double, f_console_symbol_short_enable, f_console_symbol_long_enable, " Use double quotes (default)."); + fll_program_print_help_option(file, context, fss_extended_list_write_short_object, fss_extended_list_write_long_object, f_console_symbol_short_enable, f_console_symbol_long_enable, " The Object to output."); + fll_program_print_help_option(file, context, fss_extended_list_write_short_partial, fss_extended_list_write_long_partial, f_console_symbol_short_enable, f_console_symbol_long_enable, "Do not output end of Object/Content character."); + fll_program_print_help_option(file, context, fss_extended_list_write_short_prepend, fss_extended_list_write_long_prepend, f_console_symbol_short_enable, f_console_symbol_long_enable, "Prepend the given whitespace characters to the start of each multi-line Content."); + fll_program_print_help_option(file, context, fss_extended_list_write_short_single, fss_extended_list_write_long_single, f_console_symbol_short_enable, f_console_symbol_long_enable, " Use single quotes."); + + fll_program_print_help_usage(file, context, fss_extended_list_write_name, ""); + + printf(" The pipe uses the NULL character '"); + fl_color_print(f_type_output, context.set.notable, "\\0"); + printf("' ("); + fl_color_print(f_type_output, context.set.notable, "U+0000"); + printf(") to designate the start of a Content and uses the Form Feed character '"); + fl_color_print(f_type_output, context.set.notable, "\\f"); + printf("' ("); + fl_color_print(f_type_output, context.set.notable, "U+000C"); + printf(") to designate the end of the last Content.%c", f_string_eol[0]); + printf(" For the pipe, an Object is terminated by either a NULL character '"); + fl_color_print(f_type_output, context.set.notable, "\\0"); + printf("' ("); + fl_color_print(f_type_output, context.set.notable, "U+0000"); + printf(") or a Form Feed character '"); + fl_color_print(f_type_output, context.set.notable, "\\f"); + printf("' ("); + fl_color_print(f_type_output, context.set.notable, "U+000C"); + printf(").%c", f_string_eol[0]); + printf(" The end of the pipe represents the end of any Object or Content.%c", f_string_eol[0]); + + printf("%c", f_string_eol[0]); + + printf(" The FSS-0002 (Basic List) specification does not support quoted names, therefore the parameters '"); + fl_color_print(f_type_output, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_list_write_long_single); + printf("' and '"); + fl_color_print(f_type_output, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_list_write_long_double); + printf("' do nothing.%c", f_string_eol[0]); + + printf("%c", f_string_eol[0]); + + return F_none; + } +#endif // _di_fss_extended_list_write_print_help_ + +#ifndef _di_fss_extended_list_write_main_ + f_return_status fss_extended_list_write_main(const f_console_arguments_t arguments, fss_extended_list_write_data_t *data) { + f_status_t status = F_none; + + { + const f_console_parameters_t parameters = f_macro_console_parameters_t_initialize(data->parameters, fss_extended_list_write_total_parameters); + + { + f_console_parameter_id_t ids[3] = { fss_extended_list_write_parameter_no_color, fss_extended_list_write_parameter_light, fss_extended_list_write_parameter_dark }; + const f_console_parameter_ids_t choices = f_macro_console_parameter_ids_t_initialize(ids, 3); + + status = fll_program_parameter_process(arguments, parameters, choices, F_true, &data->remaining, &data->context); + + data->error.context = data->context.set.error; + data->error.notable = data->context.set.notable; + + if (F_status_is_error(status)) { + fss_extended_list_write_delete_data(data); + return F_status_set_error(status); + } + } + + // Identify priority of verbosity related parameters. + { + f_console_parameter_id_t ids[4] = { fss_extended_list_write_parameter_verbosity_quiet, fss_extended_list_write_parameter_verbosity_normal, fss_extended_list_write_parameter_verbosity_verbose, fss_extended_list_write_parameter_verbosity_debug }; + f_console_parameter_id_t choice = 0; + const f_console_parameter_ids_t choices = f_macro_console_parameter_ids_t_initialize(ids, 4); + + status = f_console_parameter_prioritize_right(parameters, choices, &choice); + + if (F_status_is_error(status)) { + fss_extended_list_write_delete_data(data); + return status; + } + + if (choice == fss_extended_list_write_parameter_verbosity_quiet) { + data->error.verbosity = f_console_verbosity_quiet; + } + else if (choice == fss_extended_list_write_parameter_verbosity_normal) { + data->error.verbosity = f_console_verbosity_normal; + } + else if (choice == fss_extended_list_write_parameter_verbosity_verbose) { + data->error.verbosity = f_console_verbosity_verbose; + } + else if (choice == fss_extended_list_write_parameter_verbosity_debug) { + data->error.verbosity = f_console_verbosity_debug; + } + } + + status = F_none; + } + + if (data->parameters[fss_extended_list_write_parameter_help].result == f_console_result_found) { + fss_extended_list_write_print_help(data->output, data->context); + + fss_extended_list_write_delete_data(data); + return status; + } + + if (data->parameters[fss_extended_list_write_parameter_version].result == f_console_result_found) { + fll_program_print_version(data->output, fss_extended_list_write_version); + + fss_extended_list_write_delete_data(data); + return status; + } + + f_file_t output = f_file_t_initialize; + + output.id = f_type_descriptor_output; + output.stream = f_type_output; + output.flag = f_file_flag_create | f_file_flag_write_only | f_file_flag_append; + + if (F_status_is_error_not(status)) { + if (data->parameters[fss_extended_list_write_parameter_file].result == f_console_result_additional) { + if (data->parameters[fss_extended_list_write_parameter_file].additional.used > 1) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data->error.to.stream, data->context.set.error, "%sThe parameter '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_list_write_long_file); + fl_color_print(data->error.to.stream, data->context.set.error, "' may only be specified once.%c", f_string_eol[0]); + } + + status = F_status_set_error(F_parameter); + } + else { + const f_string_length_t location = data->parameters[fss_extended_list_write_parameter_file].additional.array[0]; + + output.id = -1; + output.stream = 0; + status = f_file_stream_open(arguments.argv[location], 0, &output); + + if (F_status_is_error(status)) { + fll_error_file_print(data->error, F_status_set_fine(status), "f_file_stream_open", F_true, arguments.argv[location], "open", fll_error_file_type_file); + } + } + } + else if (data->parameters[fss_extended_list_write_parameter_file].result == f_console_result_found) { + fss_extended_list_write_error_parameter_value_missing_print(*data, f_console_symbol_long_enable, fss_extended_list_write_long_file); + status = F_status_set_error(F_parameter); + } + } + + if (F_status_is_error_not(status)) { + if (data->parameters[fss_extended_list_write_parameter_object].locations.used || data->parameters[fss_extended_list_write_parameter_content].locations.used) { + if (data->parameters[fss_extended_list_write_parameter_object].locations.used) { + if (data->parameters[fss_extended_list_write_parameter_object].locations.used != data->parameters[fss_extended_list_write_parameter_object].additional.used) { + fss_extended_list_write_error_parameter_value_missing_print(*data, f_console_symbol_long_enable, fss_extended_list_write_long_object); + status = F_status_set_error(F_parameter); + } + else if (data->parameters[fss_extended_list_write_parameter_content].locations.used != data->parameters[fss_extended_list_write_parameter_content].additional.used) { + fss_extended_list_write_error_parameter_value_missing_print(*data, f_console_symbol_long_enable, fss_extended_list_write_long_content); + status = F_status_set_error(F_parameter); + } + else if (data->parameters[fss_extended_list_write_parameter_object].locations.used != data->parameters[fss_extended_list_write_parameter_content].locations.used && data->parameters[fss_extended_list_write_parameter_partial].result == f_console_result_none) { + fss_extended_list_write_error_parameter_same_times_print(*data); + status = F_status_set_error(F_parameter); + } + else if (data->parameters[fss_extended_list_write_parameter_content].locations.used && data->parameters[fss_extended_list_write_parameter_partial].locations.used) { + if (data->parameters[fss_extended_list_write_parameter_content].result == f_console_result_additional) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data->error.to.stream, data->context.set.error, "%sThe '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_list_write_long_partial); + fl_color_print(data->error.to.stream, data->context.set.error, "' parameter only allows either the '"); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_list_write_long_object); + fl_color_print(data->error.to.stream, data->context.set.error, "' parameter or the '"); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_list_write_long_content); + fl_color_print(data->error.to.stream, data->context.set.error, "' parameter, but not both.%c", f_string_eol[0]); + } + + status = F_status_set_error(F_parameter); + } + } + + if (F_status_is_error_not(status)) { + if (data->parameters[fss_extended_list_write_parameter_content].result == f_console_result_additional) { + f_array_length_t location_object = 0; + f_array_length_t location_content = 0; + f_array_length_t location_sub_object = 0; + f_array_length_t location_sub_content = 0; + + for (f_array_length_t i = 0; i < data->parameters[fss_extended_list_write_parameter_object].locations.used; i++) { + location_object = data->parameters[fss_extended_list_write_parameter_object].locations.array[i]; + location_content = data->parameters[fss_extended_list_write_parameter_content].locations.array[i]; + location_sub_object = data->parameters[fss_extended_list_write_parameter_object].locations_sub.array[i]; + location_sub_content = data->parameters[fss_extended_list_write_parameter_content].locations_sub.array[i]; + + if (location_object > location_content || location_object == location_content && location_sub_object > location_sub_content) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data->error.to.stream, data->context.set.error, "%sEach ", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_list_write_long_object); + fl_color_print(data->error.to.stream, data->context.set.error, "' parameter must be specified before a '"); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_list_write_long_content); + fl_color_print(data->error.to.stream, data->context.set.error, "' parameter.%c", f_string_eol[0]); + } + + status = F_status_set_error(F_parameter); + break; + } + } // for + } + } + } + else if (data->parameters[fss_extended_list_write_parameter_content].locations.used) { + if (data->parameters[fss_extended_list_write_parameter_content].locations.used != data->parameters[fss_extended_list_write_parameter_content].additional.used) { + fss_extended_list_write_error_parameter_value_missing_print(*data, f_console_symbol_long_enable, fss_extended_list_write_long_content); + status = F_status_set_error(F_parameter); + } + else if (!data->parameters[fss_extended_list_write_parameter_partial].locations.used) { + fss_extended_list_write_error_parameter_same_times_print(*data); + status = F_status_set_error(F_parameter); + } + } + } + else if (!data->process_pipe) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data->error.to.stream, data->context.set.error, "%sThis requires either piped data or the use of the '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_list_write_long_object); + fl_color_print(data->error.to.stream, data->context.set.error, "' parameter with the '"); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_list_write_long_content); + fl_color_print(data->error.to.stream, data->context.set.error, "' parameter.%c", f_string_eol[0]); + } + + status = F_status_set_error(F_parameter); + } + + if (F_status_is_error_not(status) && data->process_pipe) { + if (data->parameters[fss_extended_list_write_parameter_partial].result == f_console_result_found) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data->error.to.stream, data->context.set.error, "%sThe '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_list_write_long_partial); + fl_color_print(data->error.to.stream, data->context.set.error, "' parameter cannot be used when processing a pipe.%c", f_string_eol[0]); + } + + status = F_status_set_error(F_parameter); + } + } + } + + if (F_status_is_error_not(status)) { + if (data->parameters[fss_extended_list_write_parameter_prepend].result == f_console_result_found) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data->error.to.stream, data->context.set.error, "%sThe parameter '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_list_write_long_prepend); + fl_color_print(data->error.to.stream, data->context.set.error, "' was specified, but no value was given.%c", f_string_eol[0]); + } + + status = F_status_set_error(F_parameter); + } + else if (data->parameters[fss_extended_list_write_parameter_prepend].result == f_console_result_additional) { + const f_string_length_t index = data->parameters[fss_extended_list_write_parameter_prepend].additional.array[data->parameters[fss_extended_list_write_parameter_prepend].additional.used - 1]; + const f_string_length_t length = strnlen(arguments.argv[index], f_console_length_size); + + if (length) { + f_string_range_t range = f_macro_string_range_t_initialize(length); + + data->prepend.string = arguments.argv[index]; + data->prepend.used = length; + data->prepend.size = length; + + for (; range.start < length; range.start++) { + + status = f_fss_is_space(data->prepend, range); + if (F_status_is_error(status)) break; + + if (status == F_false) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data->error.to.stream, data->context.set.error, "%sThe value for the parameter '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_list_write_long_prepend); + fl_color_print(data->error.to.stream, data->context.set.error, "' must only contain whitespace.%c", f_string_eol[0]); + } + + status = F_status_set_error(F_parameter); + break; + } + } // for + } + else { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data->error.to.stream, data->context.set.error, "%sThe value for the parameter '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_list_write_long_prepend); + fl_color_print(data->error.to.stream, data->context.set.error, "' must not be an empty string.%c", f_string_eol[0]); + } + + status = F_status_set_error(F_parameter); + } + } + } + + f_fss_quote_t quote = f_fss_delimit_quote_double; + + if (F_status_is_error_not(status)) { + if (data->parameters[fss_extended_list_write_parameter_double].result == f_console_result_found) { + if (data->parameters[fss_extended_list_write_parameter_single].result == f_console_result_found) { + if (data->parameters[fss_extended_list_write_parameter_double].location < data->parameters[fss_extended_list_write_parameter_single].location) { + quote = f_fss_delimit_quote_single; + } + } + } + else if (data->parameters[fss_extended_list_write_parameter_single].result == f_console_result_found) { + quote = f_fss_delimit_quote_single; + } + } + + f_string_dynamic_t buffer = f_string_dynamic_t_initialize; + f_string_dynamic_t object = f_string_dynamic_t_initialize; + f_string_dynamic_t content = f_string_dynamic_t_initialize; + + if (F_status_is_error_not(status)) { + f_string_dynamic_t escaped = f_string_dynamic_t_initialize; + + if (data->process_pipe) { + status = fss_extended_list_write_process_pipe(*data, output, quote, &buffer); + + if (F_status_is_error(status)) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data->error.to.stream, data->context.set.error, "%sWhile processing the ", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "input pipe"); + fl_color_print(data->error.to.stream, data->context.set.error, ".%c", f_string_eol[0]); + } + } + } + + if (F_status_is_error_not(status)) { + if (data->parameters[fss_extended_list_write_parameter_partial].result == f_console_result_found) { + + if (data->parameters[fss_extended_list_write_parameter_object].result == f_console_result_additional) { + for (f_array_length_t i = 0; i < data->parameters[fss_extended_list_write_parameter_object].additional.used; i++) { + + object.string = arguments.argv[data->parameters[fss_extended_list_write_parameter_object].additional.array[i]]; + object.used = strnlen(object.string, f_console_length_size); + object.size = object.used; + + status = fss_extended_list_write_process(*data, output, quote, &object, 0, &buffer); + if (F_status_is_error(status)) break; + } // for + } + else { + for (f_array_length_t i = 0; i < data->parameters[fss_extended_list_write_parameter_content].additional.used; i++) { + + content.string = arguments.argv[data->parameters[fss_extended_list_write_parameter_content].additional.array[i]]; + content.used = strnlen(content.string, f_console_length_size); + content.size = content.used; + + status = fss_extended_list_write_process(*data, output, quote, 0, &content, &buffer); + if (F_status_is_error(status)) break; + } // for + } + } + else { + for (f_array_length_t i = 0; i < data->parameters[fss_extended_list_write_parameter_object].additional.used; i++) { + + object.string = arguments.argv[data->parameters[fss_extended_list_write_parameter_object].additional.array[i]]; + object.used = strnlen(object.string, f_console_length_size); + object.size = object.used; + + content.string = arguments.argv[data->parameters[fss_extended_list_write_parameter_content].additional.array[i]]; + content.used = strnlen(content.string, f_console_length_size); + content.size = content.used; + + status = fss_extended_list_write_process(*data, output, quote, &object, &content, &buffer); + if (F_status_is_error(status)) break; + } // for + } + + if (F_status_is_error(status)) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data->error.to.stream, data->context.set.error, "%sWhile processing the ", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "input arguments"); + fl_color_print(data->error.to.stream, data->context.set.error, ".%c", f_string_eol[0]); + } + } + else if (data->error.verbosity != f_console_verbosity_quiet && data->parameters[fss_extended_list_write_parameter_file].result == f_console_result_none) { + // ensure there is always a newline at the end, unless in quiet mode. + fprintf(f_type_output, "%c", f_string_eol[0]); + } + } + + f_macro_string_dynamic_t_delete_simple(escaped); + + // object and content, though being a "dynamic" type, is being used statically, so clear them up to avoid invalid free(). + object.string = 0; + object.used = 0; + object.size = 0; + + content.string = 0; + content.used = 0; + content.size = 0; + } + + if (data->parameters[fss_extended_list_write_parameter_file].result == f_console_result_additional) { + if (output.id != -1) { + f_file_stream_close(F_true, &output); + } + } + + // ensure a newline is always put at the end of the program execution, unless in quiet mode. + if (data->error.verbosity != f_console_verbosity_quiet) { + if (F_status_is_error(status)) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + } + } + + f_macro_string_dynamic_t_delete_simple(buffer); + f_macro_string_dynamic_t_delete_simple(object); + f_macro_string_dynamic_t_delete_simple(content); + fss_extended_list_write_delete_data(data); + return status; + } +#endif // _di_fss_extended_list_write_main_ + +#ifndef _di_fss_extended_list_write_delete_data_ + f_return_status fss_extended_list_write_delete_data(fss_extended_list_write_data_t *data) { + + for (f_string_length_t i = 0; i < fss_extended_list_write_total_parameters; i++) { + f_macro_string_lengths_t_delete_simple(data->parameters[i].locations); + f_macro_string_lengths_t_delete_simple(data->parameters[i].locations_sub); + f_macro_string_lengths_t_delete_simple(data->parameters[i].additional); + } // for + + f_macro_string_lengths_t_delete_simple(data->remaining); + + f_macro_color_context_t_delete_simple(data->context); + + return F_none; + } +#endif // _di_fss_extended_list_write_delete_data_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_3/fss_extended_list_write/c/fss_extended_list_write.h b/level_3/fss_extended_list_write/c/fss_extended_list_write.h new file mode 100644 index 0000000..e254405 --- /dev/null +++ b/level_3/fss_extended_list_write/c/fss_extended_list_write.h @@ -0,0 +1,204 @@ +/** + * FLL - Level 3 + * + * Project: FSS + * API Version: 0.5 + * Licenses: lgplv2.1 + * + * This program provides fss basic list write functionality. + */ +#ifndef _fss_extended_list_write_h + +// libc includes +#include +#include +#include + +// fll-0 includes +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// fll-1 includes +#include +#include +#include +#include +#include + +// fll-2 includes +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fss_extended_list_write_version_ + #define fss_extended_list_write_major_version "0" + #define fss_extended_list_write_minor_version "5" + #define fss_extended_list_write_micro_version "1" + #define fss_extended_list_write_version fss_extended_list_write_major_version "." fss_extended_list_write_minor_version "." fss_extended_list_write_micro_version +#endif // _di_fss_extended_list_write_version_ + +#ifndef _di_fss_extended_list_write_name_ + #define fss_extended_list_write_name "fss_extended_list_write" + #define fss_extended_list_write_name_long "FSS Basic List Write" +#endif // _di_fss_extended_list_write_name_ + +#ifndef _di_fss_extended_list_write_defines_ + #define fss_extended_list_write_pipe_content_start '\0' + #define fss_extended_list_write_pipe_content_end '\f' + + #define fss_extended_list_write_short_file "f" + #define fss_extended_list_write_short_content "c" + #define fss_extended_list_write_short_double "d" + #define fss_extended_list_write_short_object "o" + #define fss_extended_list_write_short_partial "p" + #define fss_extended_list_write_short_prepend "P" + #define fss_extended_list_write_short_single "s" + + #define fss_extended_list_write_long_file "file" + #define fss_extended_list_write_long_content "content" + #define fss_extended_list_write_long_double "double" + #define fss_extended_list_write_long_object "object" + #define fss_extended_list_write_long_partial "partial" + #define fss_extended_list_write_long_prepend "prepend" + #define fss_extended_list_write_long_single "single" + + enum { + fss_extended_list_write_parameter_help, + fss_extended_list_write_parameter_light, + fss_extended_list_write_parameter_dark, + fss_extended_list_write_parameter_no_color, + fss_extended_list_write_parameter_verbosity_quiet, + fss_extended_list_write_parameter_verbosity_normal, + fss_extended_list_write_parameter_verbosity_verbose, + fss_extended_list_write_parameter_verbosity_debug, + fss_extended_list_write_parameter_version, + + fss_extended_list_write_parameter_file, + fss_extended_list_write_parameter_content, + fss_extended_list_write_parameter_double, + fss_extended_list_write_parameter_object, + fss_extended_list_write_parameter_partial, + fss_extended_list_write_parameter_prepend, + fss_extended_list_write_parameter_single, + }; + + #define fss_extended_list_write_console_parameter_t_initialize \ + { \ + f_console_parameter_t_initialize(f_console_standard_short_help, f_console_standard_long_help, 0, 0, f_console_type_normal), \ + f_console_parameter_t_initialize(f_console_standard_short_light, f_console_standard_long_light, 0, 0, f_console_type_inverse), \ + f_console_parameter_t_initialize(f_console_standard_short_dark, f_console_standard_long_dark, 0, 0, f_console_type_inverse), \ + f_console_parameter_t_initialize(f_console_standard_short_no_color, f_console_standard_long_no_color, 0, F_false, f_console_type_inverse), \ + f_console_parameter_t_initialize(f_console_standard_short_quiet, f_console_standard_long_quiet, 0, 0, f_console_type_inverse), \ + f_console_parameter_t_initialize(f_console_standard_short_normal, f_console_standard_long_normal, 0, 0, f_console_type_inverse), \ + f_console_parameter_t_initialize(f_console_standard_short_verbose, f_console_standard_long_verbose, 0, 0, f_console_type_inverse), \ + f_console_parameter_t_initialize(f_console_standard_short_debug, f_console_standard_long_debug, 0, 0, f_console_type_inverse), \ + f_console_parameter_t_initialize(f_console_standard_short_version, f_console_standard_long_version, 0, 0, f_console_type_inverse), \ + f_console_parameter_t_initialize(fss_extended_list_write_short_file, fss_extended_list_write_long_file, 0, 1, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_extended_list_write_short_content, fss_extended_list_write_long_content, 0, 1, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_extended_list_write_short_double, fss_extended_list_write_long_double, 0, 0, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_extended_list_write_short_object, fss_extended_list_write_long_object, 0, 1, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_extended_list_write_short_partial, fss_extended_list_write_long_partial, 0, 0, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_extended_list_write_short_prepend, fss_extended_list_write_long_prepend, 0, 1, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_extended_list_write_short_single, fss_extended_list_write_long_single, 0, 0, f_console_type_normal), \ + } + + #define fss_extended_list_write_total_parameters 16 +#endif // _di_fss_extended_list_write_defines_ + +#ifndef _di_fss_extended_list_write_data_t_ + typedef struct { + f_console_parameter_t parameters[fss_extended_list_write_total_parameters]; + + f_string_lengths_t remaining; + bool process_pipe; + + f_file_t output; + fll_error_print_t error; + f_string_static_t prepend; + + f_color_context_t context; + } fss_extended_list_write_data_t; + + #define fss_extended_list_write_data_t_initialize \ + { \ + fss_extended_list_write_console_parameter_t_initialize, \ + f_string_lengths_t_initialize, \ + F_false, \ + f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \ + fll_error_print_t_initialize, \ + f_string_static_t_initialize, \ + f_color_context_t_initialize, \ + } +#endif // _di_fss_extended_list_write_data_t_ + +/** + * Print help. + * + * @param file + * The file to print to. + * @param context + * The color context settings. + * + * @return + * F_none on success. + */ +#ifndef _di_fss_extended_list_write_print_help_ + extern f_return_status fss_extended_list_write_print_help(const f_file_t file, const f_color_context_t context); +#endif // _di_fss_extended_list_write_print_help_ + +/** + * Execute main program. + * + * Be sure to call fss_extended_list_write_delete_data() after executing this. + * + * @param arguments + * The parameters passed to the process. + * @param data + * The program data. + * + * @return + * F_none on success. + * + * Status codes (with error bit) are returned on any problem. + * + * @see fss_extended_list_write_delete_data() + */ +#ifndef _di_fss_extended_list_write_main_ + extern f_return_status fss_extended_list_write_main(const f_console_arguments_t arguments, fss_extended_list_write_data_t *data); +#endif // _di_fss_extended_list_write_main_ + +/** + * Deallocate data. + * + * Be sure to call this after executing fss_extended_list_write_main(). + * + * @param data + * The program data. + * + * @return + * F_none on success. + * + * Status codes (with error bit) are returned on any problem. + * + * @see fss_extended_list_write_main() + */ +#ifndef _di_fss_extended_list_write_delete_data_ + extern f_return_status fss_extended_list_write_delete_data(fss_extended_list_write_data_t *data); +#endif // _di_fss_extended_list_write_delete_data_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _fss_extended_list_write_h diff --git a/level_3/fss_extended_list_write/c/main.c b/level_3/fss_extended_list_write/c/main.c new file mode 100644 index 0000000..2360d4d --- /dev/null +++ b/level_3/fss_extended_list_write/c/main.c @@ -0,0 +1,16 @@ +#include "fss_extended_list_write.h" + +int main(const unsigned long argc, const f_string_t *argv) { + const f_console_arguments_t arguments = { argc, argv }; + fss_extended_list_write_data_t data = fss_extended_list_write_data_t_initialize; + + if (f_pipe_input_exists()) { + data.process_pipe = F_true; + } + + if (F_status_is_error(fss_extended_list_write_main(arguments, &data))) { + return 1; + } + + return 0; +} diff --git a/level_3/fss_extended_list_write/c/private-fss_extended_list_write.c b/level_3/fss_extended_list_write/c/private-fss_extended_list_write.c new file mode 100644 index 0000000..72fa0b0 --- /dev/null +++ b/level_3/fss_extended_list_write/c/private-fss_extended_list_write.c @@ -0,0 +1,266 @@ +#include "fss_extended_list_write.h" +#include "private-fss_extended_list_write.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fss_extended_list_write_error_parameter_same_times_print_ + void fss_extended_list_write_error_parameter_same_times_print(const fss_extended_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, "%sMust specify both the '", fll_error_print_error); + fl_color_print(data.error.to.stream, data.context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_list_write_long_object); + fl_color_print(data.error.to.stream, data.context.set.error, "' parameter and the '"); + fl_color_print(data.error.to.stream, data.context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_list_write_long_content); + fl_color_print(data.error.to.stream, data.context.set.error, "' parameter the same number of times when not specifying the "); + fl_color_print(data.error.to.stream, data.context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_list_write_long_partial); + fl_color_print(data.error.to.stream, data.context.set.error, "' parameter.%c", f_string_eol[0]); + } +#endif // _di_fss_extended_list_write_error_parameter_same_times_print_ + +#ifndef _di_fss_extended_list_write_error_parameter_unsupported_eol_print_ + void fss_extended_list_write_error_parameter_unsupported_eol_print(const fss_extended_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_extended_list_write_error_parameter_unsupported_eol_print_ + +#ifndef _di_fss_extended_list_write_error_parameter_value_missing_print_ + void fss_extended_list_write_error_parameter_value_missing_print(const fss_extended_list_write_data_t data, const f_string_t symbol, const f_string_t parameter) { + + 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, "%sThe parameter '", fll_error_print_error); + fl_color_print(data.error.to.stream, data.context.set.notable, "%s%s", symbol, parameter); + fl_color_print(data.error.to.stream, data.context.set.error, "' was specified, but no value was given.%c", f_string_eol[0]); + } +#endif // _di_fss_extended_list_write_error_parameter_value_missing_print_ + +#ifndef _di_fss_extended_list_write_process_ + f_return_status fss_extended_list_write_process(const fss_extended_list_write_data_t data, const f_file_t output, const f_fss_quote_t quote, const f_string_static_t *object, const f_string_static_t *content, f_string_dynamic_t *buffer) { + f_status_t status = F_none; + + f_string_range_t range = f_string_range_t_initialize; + + if (object) { + if (object->used) { + range.start = 0; + range.stop = object->used - 1; + } + else { + range.start = 1; + range.stop = 0; + } + + status = fl_fss_extended_list_object_write(*object, content ? f_fss_complete_full : f_fss_complete_none, &range, buffer); + + if (F_status_set_fine(status) == F_none_eol) { + fss_extended_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_extended_list_object_write", F_true); + return status; + } + } + + if (content && content->used) { + range.start = 0; + range.stop = content->used - 1; + + status = fl_fss_extended_list_content_write(*content, object ? f_fss_complete_full : f_fss_complete_none, data.prepend, &range, buffer); + + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "fl_fss_extended_list_content_write", F_true); + return status; + } + } + + if (!object || !content) { + status = fl_string_append(f_string_eol, 1, buffer); + + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "fl_string_append", F_true); + return status; + } + } + + f_print_dynamic(output.stream, *buffer); + + buffer->used = 0; + return status; + } +#endif // _di_fss_extended_list_write_process_ + +#ifndef _di_fss_extended_list_write_process_pipe_ + f_return_status fss_extended_list_write_process_pipe(const fss_extended_list_write_data_t data, const f_file_t output, const f_fss_quote_t quote, f_string_dynamic_t *buffer) { + f_status_t status = F_none; + f_status_t status_pipe = F_none; + + f_file_t input = f_file_t_initialize; + + input.id = f_type_descriptor_input; + input.size_read = 2048; + + f_string_length_t total = 0; + f_string_length_t previous = 0; + f_string_range_t range = f_string_range_t_initialize; + + f_string_dynamic_t block = f_string_dynamic_t_initialize; + f_string_dynamic_t object = f_string_dynamic_t_initialize; + f_string_dynamic_t content = f_string_dynamic_t_initialize; + + // 0x0 = start new object/content set, 0x1 = processing object, 0x2 = processing content, 0x3 = end object/content set. + uint8_t state = 0; + + for (;;) { + + if (range.start > range.stop) { + if (status_pipe == F_none_eof) break; + + block.used = 0; + + status_pipe = f_file_read_block(input, &block); + + if (F_status_is_error(status_pipe)) { + fll_error_print(data.error, F_status_set_fine(status_pipe), "f_file_read_block", F_true); + + status_pipe = F_status_set_error(F_pipe); + break; + } + + if (!block.used) break; + + range.start = 0; + range.stop = block.used - 1; + } + + if (!state || state == 0x1) { + if (!state) { + object.used = 0; + content.used = 0; + + state = 0x1; + } + + if (object.used + block.used > object.size) { + status = fl_string_dynamic_size_increase(block.used, &object); + + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_size_increase", F_true); + break; + } + } + + for (; range.start <= range.stop; range.start++) { + + if (block.string[range.start] == fss_extended_list_write_pipe_content_start) { + state = 0x2; + range.start++; + break; + } + + if (block.string[range.start] == fss_extended_list_write_pipe_content_end) { + state = 0x3; + range.start++; + break; + } + + object.string[object.used++] = block.string[range.start]; + } // for + + if (F_status_is_error(status)) break; + + // if the start of content was not found, then fetch the next block. + if (state == 0x1) continue; + + // if the end of the current block is reached, fetch the next block. + if (range.start > range.stop) continue; + } + + if (state == 0x2) { + if (range.start <= range.stop) { + total = (range.stop - range.start) + 1; + } + else { + total = 0; + } + + if (total) { + if (content.used + total > content.size) { + status = fl_string_dynamic_size_increase(total, &content); + + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_size_increase", F_true); + break; + } + } + + for (; range.start <= range.stop; range.start++) { + + if (block.string[range.start] == fss_extended_list_write_pipe_content_start) { + if (data.error.verbosity != f_console_verbosity_quiet) { + fprintf(data.error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data.error.to.stream, data.context.set.error, "%sThis standard only supports one content per object.%c", fll_error_print_error, f_string_eol[0]); + } + + status = F_status_set_error(F_unsupported); + break; + } + + if (block.string[range.start] == fss_extended_list_write_pipe_content_end) { + state = 0x3; + range.start++; + break; + } + + content.string[content.used++] = block.string[range.start]; + } // for + + if (F_status_is_error(status)) break; + } + else { + state = 0x3; + } + } + + if (state == 0x3) { + status = fss_extended_list_write_process(data, output, quote, &object, &content, buffer); + if (F_status_is_error(status)) break; + + state = 0; + } + } // for + + // if the pipe ended before finishing, then attempt to wrap up. + if (F_status_is_error_not(status) && status_pipe == F_none_eof && state) { + status = fss_extended_list_write_process(data, output, quote, &object, &content, buffer); + } + + f_macro_string_dynamic_t_delete_simple(block); + f_macro_string_dynamic_t_delete_simple(object); + f_macro_string_dynamic_t_delete_simple(content); + return status; + } +#endif // _di_fss_extended_list_write_process_pipe_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_3/fss_extended_list_write/c/private-fss_extended_list_write.h b/level_3/fss_extended_list_write/c/private-fss_extended_list_write.h new file mode 100644 index 0000000..ed984b7 --- /dev/null +++ b/level_3/fss_extended_list_write/c/private-fss_extended_list_write.h @@ -0,0 +1,111 @@ +/** + * FLL - Level 3 + * + * Project: FSS + * API Version: 0.5 + * Licenses: lgplv2.1 + */ +#ifndef _PRIVATE_fss_extended_list_write_h +#define _PRIVATE_fss_extended_list_write_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Print an message about the object and content parameters not being specified the same number of times. + * + * @param data + * The program data. + * + * @return + * F_none on success. + * F_failure (with error bit) for any othe failure. + */ +#ifndef _di_fss_extended_list_write_error_parameter_same_times_print_ + void fss_extended_list_write_error_parameter_same_times_print(const fss_extended_list_write_data_t data) f_gcc_attribute_visibility_internal; +#endif // _di_fss_extended_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_extended_list_write_error_parameter_unsupported_eol_print_ + void fss_extended_list_write_error_parameter_unsupported_eol_print(const fss_extended_list_write_data_t data) f_gcc_attribute_visibility_internal; +#endif // _di_fss_extended_list_write_error_parameter_unsupported_eol_print_ + +/** + * Print an message about a parameter missing a value. + * + * @param data + * The program data. + * @param symbol + * The console symbol, such as "--" in "--help". + * @param parameter + * The parameter name, such as "help" in "--help". + * + * @return + * F_none on success. + * F_failure (with error bit) for any othe failure. + */ +#ifndef _di_fss_extended_list_write_error_parameter_value_missing_print_ + void fss_extended_list_write_error_parameter_value_missing_print(const fss_extended_list_write_data_t data, const f_string_t symbol, const f_string_t parameter) f_gcc_attribute_visibility_internal; +#endif // _di_fss_extended_list_write_error_parameter_value_missing_print_ + +/** + * Process a given object and content, printing the FSS if valid or an error if invalid. + * + * @param data + * The program data. + * @param output + * The file to output to. + * @param quote + * The quote character to use. + * This is either single our double quote. + * @param object + * The object to validate and print. + * @param content + * The content to escape and print. + * @param buffer + * The buffer array used as a cache to construct the output before printing. + * + * @return + * F_none on success. + * F_failure (with error bit) for any othe failure. + */ +#ifndef _di_fss_extended_list_write_process_ + extern f_return_status fss_extended_list_write_process(const fss_extended_list_write_data_t data, const f_file_t output, const f_fss_quote_t quote, const f_string_static_t *object, const f_string_static_t *content, f_string_dynamic_t *buffer) f_gcc_attribute_visibility_internal; +#endif // _di_fss_extended_list_write_process_ + +/** + * Process the pipe, reading from the pipe and writing to the output. + * + * @param data + * The program data. + * @param output + * The file to output to. + * @param quote + * The quote character to use. + * This is either single our double quote. + * @param buffer + * The buffer array used as a cache to construct the output before printing. + * + * @return + * F_none on success. + * F_failure (with error bit) for any othe failure. + */ +#ifndef _di_fss_extended_list_write_process_pipe_ + extern f_return_status fss_extended_list_write_process_pipe(const fss_extended_list_write_data_t data, const f_file_t output, const f_fss_quote_t quote, f_string_dynamic_t *buffer) f_gcc_attribute_visibility_internal; +#endif // _di_fss_extended_list_write_process_pipe_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _PRIVATE_fss_extended_list_write_h diff --git a/level_3/fss_extended_list_write/data/build/defines b/level_3/fss_extended_list_write/data/build/defines new file mode 100644 index 0000000..c665317 --- /dev/null +++ b/level_3/fss_extended_list_write/data/build/defines @@ -0,0 +1,2 @@ +# fss-0000 + diff --git a/level_3/fss_extended_list_write/data/build/dependencies b/level_3/fss_extended_list_write/data/build/dependencies new file mode 100644 index 0000000..35c97b5 --- /dev/null +++ b/level_3/fss_extended_list_write/data/build/dependencies @@ -0,0 +1,26 @@ +# fss-0000 + +f_type +f_status +f_memory +f_string +f_utf +f_color +f_console +f_directory +f_environment +f_file +f_fss +f_pipe +f_print +fl_color +fl_console +fl_conversion +fl_fss +fl_status +fl_string +fll_error +fll_execute +fll_file +fll_fss +fll_program diff --git a/level_3/fss_extended_list_write/data/build/settings b/level_3/fss_extended_list_write/data/build/settings new file mode 100644 index 0000000..1ea864c --- /dev/null +++ b/level_3/fss_extended_list_write/data/build/settings @@ -0,0 +1,56 @@ +# fss-0001 + +project_name fss_extended_list_write + +version_major 0 +version_minor 5 +version_micro 1 +version_target major + +environment + +process_pre +process_post + +modes individual level monolithic +modes_default individual + +build_compiler gcc +build_indexer ar +build_language c +build_libraries -lc +build_libraries-individual -lfll_program -lfll_fss -lfll_file -lfl_directory -lfll_execute -lfl_environment -lf_signal -lf_path -lfll_error -lfl_string -lfl_status -lfl_fss -lfl_conversion -lfl_console -lf_conversion -lfl_color -lf_print -lf_pipe -lf_fss -lf_file -lf_environment -lf_directory -lf_console -lf_utf -lf_memory +build_libraries-level -lfll_2 -lfll_1 -lfll_0 +build_libraries-monolithic -lfll +build_sources_library fss_extended_list_write.c private-fss_extended_list_write.c +build_sources_program main.c +build_sources_headers fss_extended_list_write.h +build_sources_script +build_sources_setting +build_script yes +build_shared yes +build_static yes + +path_headers level_3 +path_library_script script +path_library_shared shared +path_library_static static +path_program_script script +path_program_shared shared +path_program_static static +path_sources +path_standard yes + +search_exclusive yes +search_shared yes +search_static yes + +defines_all +defines_static +defines_shared + +flags_all -z now -g -fdiagnostics-color=always +flags_shared +flags_static +flags_library -fPIC +flags_program -fPIE diff --git a/level_3/fss_extended_write/c/fss_extended_write.c b/level_3/fss_extended_write/c/fss_extended_write.c index 74dc681..08845b5 100644 --- a/level_3/fss_extended_write/c/fss_extended_write.c +++ b/level_3/fss_extended_write/c/fss_extended_write.c @@ -23,10 +23,11 @@ extern "C" { printf("%c", f_string_eol[0]); fll_program_print_help_option(file, context, fss_extended_write_short_file, fss_extended_write_long_file, f_console_symbol_short_enable, f_console_symbol_long_enable, " Specify a file to send output to."); - fll_program_print_help_option(file, context, fss_extended_write_short_content, fss_extended_write_long_content, f_console_symbol_short_enable, f_console_symbol_long_enable, "The content to output."); + fll_program_print_help_option(file, context, fss_extended_write_short_content, fss_extended_write_long_content, f_console_symbol_short_enable, f_console_symbol_long_enable, "The Content to output."); fll_program_print_help_option(file, context, fss_extended_write_short_double, fss_extended_write_long_double, f_console_symbol_short_enable, f_console_symbol_long_enable, " Use double quotes (default)."); - fll_program_print_help_option(file, context, fss_extended_write_short_object, fss_extended_write_long_object, f_console_symbol_short_enable, f_console_symbol_long_enable, " The object to output."); - fll_program_print_help_option(file, context, fss_extended_write_short_partial, fss_extended_write_long_partial, f_console_symbol_short_enable, f_console_symbol_long_enable, "Do not output end of object/content character."); + fll_program_print_help_option(file, context, fss_extended_write_short_object, fss_extended_write_long_object, f_console_symbol_short_enable, f_console_symbol_long_enable, " The Object to output."); + fll_program_print_help_option(file, context, fss_extended_write_short_partial, fss_extended_write_long_partial, f_console_symbol_short_enable, f_console_symbol_long_enable, "Do not output end of Object/Content character."); + fll_program_print_help_option(file, context, fss_extended_write_short_prepend, fss_extended_write_long_prepend, f_console_symbol_short_enable, f_console_symbol_long_enable, "Prepend the given whitespace characters to the start of each multi-line Content."); fll_program_print_help_option(file, context, fss_extended_write_short_single, fss_extended_write_long_single, f_console_symbol_short_enable, f_console_symbol_long_enable, " Use single quotes."); fll_program_print_help_usage(file, context, fss_extended_write_name, ""); @@ -53,6 +54,12 @@ extern "C" { printf("%c", f_string_eol[0]); + printf(" The FSS-0001 (Extended) specification does not support multi-line Content, therefore the parameter '"); + fl_color_print(f_type_output, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_write_long_prepend); + printf("' does nothing.%c", f_string_eol[0]); + + printf("%c", f_string_eol[0]); + return F_none; } #endif // _di_fss_extended_write_print_help_ @@ -270,6 +277,57 @@ extern "C" { } } + if (F_status_is_error_not(status)) { + if (data->parameters[fss_extended_write_parameter_prepend].result == f_console_result_found) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data->error.to.stream, data->context.set.error, "%sThe parameter '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_write_long_prepend); + fl_color_print(data->error.to.stream, data->context.set.error, "' was specified, but no value was given.%c", f_string_eol[0]); + } + + status = F_status_set_error(F_parameter); + } + else if (data->parameters[fss_extended_write_parameter_prepend].result == f_console_result_additional) { + const f_string_length_t index = data->parameters[fss_extended_write_parameter_prepend].additional.array[data->parameters[fss_extended_write_parameter_prepend].additional.used - 1]; + const f_string_length_t length = strnlen(arguments.argv[index], f_console_length_size); + + // Even though this standard does not utilize this parameter, provide the validation for consistency. + if (length) { + f_string_range_t range = f_macro_string_range_t_initialize(length); + const f_string_static_t prepend = f_macro_string_static_t_initialize(arguments.argv[index], length); + + for (; range.start < length; range.start++) { + + status = f_fss_is_space(prepend, range); + if (F_status_is_error(status)) break; + + if (status == F_false) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data->error.to.stream, data->context.set.error, "%sThe value for the parameter '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_write_long_prepend); + fl_color_print(data->error.to.stream, data->context.set.error, "' must only contain whitespace.%c", f_string_eol[0]); + } + + status = F_status_set_error(F_parameter); + break; + } + } // for + } + else { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data->error.to.stream, data->context.set.error, "%sThe value for the parameter '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_extended_write_long_prepend); + fl_color_print(data->error.to.stream, data->context.set.error, "' must not be an empty string.%c", f_string_eol[0]); + } + + status = F_status_set_error(F_parameter); + } + } + } + f_fss_quote_t quote = f_fss_delimit_quote_double; if (F_status_is_error_not(status)) { @@ -333,7 +391,9 @@ extern "C" { fll_error_print(data->error, F_status_set_fine(status), "fl_string_dynamics_size_increase", F_true); } else { - for (f_array_length_t i = 0; i < data->parameters[fss_extended_write_parameter_content].additional.used; i++) { + f_array_length_t i = 0; + + for (; i < data->parameters[fss_extended_write_parameter_content].additional.used; i++) { contents.array[contents.used].string = arguments.argv[data->parameters[fss_extended_write_parameter_content].additional.array[i]]; contents.array[contents.used].used = strnlen(contents.array[contents.used].string, f_console_length_size); @@ -342,6 +402,16 @@ extern "C" { } // for status = fss_extended_write_process(*data, output, quote, 0, &contents, &buffer); + + // clear the contents array of the static strings to avoid deallocation attempts on static variables. + for (; i < data->parameters[fss_extended_write_parameter_content].additional.used; i++) { + contents.array[contents.used].string = 0; + contents.array[contents.used].used = 0; + contents.array[contents.used].size = 0; + } // for + + contents.used = 0; + contents.size = 0; } } } diff --git a/level_3/fss_extended_write/c/fss_extended_write.h b/level_3/fss_extended_write/c/fss_extended_write.h index 56925a4..8c5d4d2 100644 --- a/level_3/fss_extended_write/c/fss_extended_write.h +++ b/level_3/fss_extended_write/c/fss_extended_write.h @@ -62,6 +62,7 @@ extern "C" { #define fss_extended_write_short_double "d" #define fss_extended_write_short_object "o" #define fss_extended_write_short_partial "p" + #define fss_extended_write_short_prepend "P" #define fss_extended_write_short_single "s" #define fss_extended_write_long_file "file" @@ -69,6 +70,7 @@ extern "C" { #define fss_extended_write_long_double "double" #define fss_extended_write_long_object "object" #define fss_extended_write_long_partial "partial" + #define fss_extended_write_long_prepend "prepend" #define fss_extended_write_long_single "single" enum { @@ -87,6 +89,7 @@ extern "C" { fss_extended_write_parameter_double, fss_extended_write_parameter_object, fss_extended_write_parameter_partial, + fss_extended_write_parameter_prepend, fss_extended_write_parameter_single, }; @@ -106,10 +109,11 @@ extern "C" { f_console_parameter_t_initialize(fss_extended_write_short_double, fss_extended_write_long_double, 0, 0, f_console_type_normal), \ f_console_parameter_t_initialize(fss_extended_write_short_object, fss_extended_write_long_object, 0, 1, f_console_type_normal), \ f_console_parameter_t_initialize(fss_extended_write_short_partial, fss_extended_write_long_partial, 0, 0, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_extended_write_short_prepend, fss_extended_write_long_prepend, 0, 1, f_console_type_normal), \ f_console_parameter_t_initialize(fss_extended_write_short_single, fss_extended_write_long_single, 0, 0, f_console_type_normal), \ } - #define fss_extended_write_total_parameters 15 + #define fss_extended_write_total_parameters 16 #endif // _di_fss_extended_write_defines_ #ifndef _di_fss_extended_write_data_t_ @@ -121,6 +125,7 @@ extern "C" { f_file_t output; fll_error_print_t error; + f_string_static_t prepend; f_color_context_t context; } fss_extended_write_data_t; @@ -132,6 +137,7 @@ extern "C" { F_false, \ f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \ fll_error_print_t_initialize, \ + f_string_static_t_initialize, \ f_color_context_t_initialize, \ } #endif // _di_fss_extended_write_data_t_ diff --git a/level_3/fss_extended_write/c/private-fss_extended_write.c b/level_3/fss_extended_write/c/private-fss_extended_write.c index 425b8f9..dcdf8ff 100644 --- a/level_3/fss_extended_write/c/private-fss_extended_write.c +++ b/level_3/fss_extended_write/c/private-fss_extended_write.c @@ -67,7 +67,7 @@ extern "C" { range.stop = 0; } - status = fl_fss_extended_object_write(*object, quote, contents && contents->used ? f_fss_complete_full : f_fss_complete_partial, &range, buffer); + status = fl_fss_extended_object_write(*object, quote, contents && contents->used ? f_fss_complete_full : f_fss_complete_none, &range, buffer); if (F_status_set_fine(status) == F_none_eol) { fss_extended_write_error_parameter_unsupported_eol_print(data); @@ -108,14 +108,13 @@ extern "C" { } } // for } - else { - // objects in this standard do not have EOL, so add an EOL for printing purposes when there is no desired content. - status = fl_string_append(f_string_eol, 1, buffer); + } + else if (!object) { + status = fl_string_append(f_string_eol, 1, buffer); - if (F_status_is_error(status)) { - fll_error_print(data.error, F_status_set_fine(status), "fl_string_append", F_true); - return status; - } + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "fl_string_append", F_true); + return status; } } -- 1.8.3.1