From 5d85361bc5fc205b9bbad61daa395cac087e310c Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Fri, 13 Nov 2020 23:33:15 -0600 Subject: [PATCH] Update: create FSS Embedded List and other minor fixes. The FSS-0008 Embedded List is just copied from FSS-0003 Extended List. Fix some minor problems observed during this transition. I will need to follow up with rewriting the FSS-0003 Extended List code. I will probably just use FSS-0002 Basic List as a fresh starting point given that list is not recursive. --- build/level_1/settings | 4 +- build/level_2/settings | 4 +- build/monolithic/settings | 4 +- level_0/f_fss/c/fss-common.h | 7 +- level_1/fl_fss/c/fss_basic.h | 2 +- level_1/fl_fss/c/fss_basic_list.h | 2 +- level_1/fl_fss/c/fss_embedded_list.c | 1300 ++++++++++++++++++++ level_1/fl_fss/c/fss_embedded_list.h | 225 ++++ level_1/fl_fss/c/fss_extended.h | 2 +- level_1/fl_fss/c/fss_extended_list.h | 4 +- level_1/fl_fss/data/build/settings | 4 +- level_2/fll_fss/c/fss_embedded_list.c | 151 +++ level_2/fll_fss/c/fss_embedded_list.h | 118 ++ level_2/fll_fss/data/build/settings | 4 +- .../c/fss_embedded_list_read.c | 529 ++++++++ .../c/fss_embedded_list_read.h | 263 ++++ level_3/fss_embedded_list_read/c/main.c | 16 + .../c/private-fss_embedded_list_read.c | 894 ++++++++++++++ .../c/private-fss_embedded_list_read.h | 396 ++++++ level_3/fss_embedded_list_read/data/build/defines | 2 + .../fss_embedded_list_read/data/build/dependencies | 27 + level_3/fss_embedded_list_read/data/build/settings | 57 + .../c/fss_embedded_list_write.c | 529 ++++++++ .../c/fss_embedded_list_write.h | 214 ++++ level_3/fss_embedded_list_write/c/main.c | 16 + .../c/private-fss_embedded_list_write.c | 409 ++++++ .../c/private-fss_embedded_list_write.h | 129 ++ level_3/fss_embedded_list_write/data/build/defines | 2 + .../data/build/dependencies | 26 + .../fss_embedded_list_write/data/build/settings | 57 + .../c/fss_extended_list_write.h | 4 +- 31 files changed, 5384 insertions(+), 17 deletions(-) create mode 100644 level_1/fl_fss/c/fss_embedded_list.c create mode 100644 level_1/fl_fss/c/fss_embedded_list.h create mode 100644 level_2/fll_fss/c/fss_embedded_list.c create mode 100644 level_2/fll_fss/c/fss_embedded_list.h create mode 100644 level_3/fss_embedded_list_read/c/fss_embedded_list_read.c create mode 100644 level_3/fss_embedded_list_read/c/fss_embedded_list_read.h create mode 100644 level_3/fss_embedded_list_read/c/main.c create mode 100644 level_3/fss_embedded_list_read/c/private-fss_embedded_list_read.c create mode 100644 level_3/fss_embedded_list_read/c/private-fss_embedded_list_read.h create mode 100644 level_3/fss_embedded_list_read/data/build/defines create mode 100644 level_3/fss_embedded_list_read/data/build/dependencies create mode 100644 level_3/fss_embedded_list_read/data/build/settings create mode 100644 level_3/fss_embedded_list_write/c/fss_embedded_list_write.c create mode 100644 level_3/fss_embedded_list_write/c/fss_embedded_list_write.h create mode 100644 level_3/fss_embedded_list_write/c/main.c create mode 100644 level_3/fss_embedded_list_write/c/private-fss_embedded_list_write.c create mode 100644 level_3/fss_embedded_list_write/c/private-fss_embedded_list_write.h create mode 100644 level_3/fss_embedded_list_write/data/build/defines create mode 100644 level_3/fss_embedded_list_write/data/build/dependencies create mode 100644 level_3/fss_embedded_list_write/data/build/settings diff --git a/build/level_1/settings b/build/level_1/settings index 3530295..3f4a43a 100644 --- a/build/level_1/settings +++ b/build/level_1/settings @@ -20,9 +20,9 @@ build_indexer ar build_language c build_libraries -lc build_libraries-level -lfll_0 -build_sources_library color.c console.c conversion.c directory.c private-directory.c environment.c private-fss.c fss_basic.c fss_basic_list.c fss_extended.c fss_extended_list.c iki.c print.c private-print.c status.c string.c private-string.c utf.c private-utf.c utf_file.c private-utf_file.c +build_sources_library color.c console.c conversion.c directory.c private-directory.c environment.c private-fss.c fss_basic.c fss_basic_list.c fss_embedded_list.c fss_extended.c fss_extended_list.c iki.c print.c private-print.c status.c string.c private-string.c utf.c private-utf.c utf_file.c private-utf_file.c build_sources_program -build_sources_headers color.h console.h conversion.h directory.h environment.h fss.h fss_basic.h fss_basic_list.h fss_extended.h fss_extended_list.h fss_macro.h fss_status.h iki.h print.h status.h string.h utf.h utf_file.h +build_sources_headers color.h console.h conversion.h directory.h environment.h fss.h fss_basic.h fss_basic_list.h fss_embedded_list.h fss_extended.h fss_extended_list.h fss_macro.h fss_status.h iki.h print.h status.h string.h utf.h utf_file.h build_sources_script build_sources_setting build_script yes diff --git a/build/level_2/settings b/build/level_2/settings index d6c04fc..55ea710 100644 --- a/build/level_2/settings +++ b/build/level_2/settings @@ -20,9 +20,9 @@ build_indexer ar build_language c build_libraries -lc build_libraries-level -lfll_1 -lfll_0 -build_sources_library error.c private-error.c execute.c private-execute.c file.c private-file.c fss.c private-fss.c fss_basic.c fss_basic_list.c fss_extended.c fss_extended_list.c fss_status.c iki.c private-iki.c path.c program.c status.c +build_sources_library error.c private-error.c execute.c private-execute.c file.c private-file.c fss.c private-fss.c fss_basic.c fss_basic_list.c fss_embedded_list.c fss_extended.c fss_extended_list.c fss_status.c iki.c private-iki.c path.c program.c status.c build_sources_program -build_sources_headers error.h error-common.h execute.h file.h fss.h fss_basic.h fss_basic_list.h fss_extended.h fss_extended_list.h fss_status.h iki.h path.h program.h status.h +build_sources_headers error.h error-common.h execute.h file.h fss.h fss_basic.h fss_basic_list.h fss_embedded_list.h fss_extended.h fss_extended_list.h fss_status.h iki.h path.h program.h status.h build_sources_script build_sources_setting build_script yes diff --git a/build/monolithic/settings b/build/monolithic/settings index 2ae883a..5425292 100644 --- a/build/monolithic/settings +++ b/build/monolithic/settings @@ -20,9 +20,9 @@ build_indexer ar build_language c build_libraries -lc build_libraries-monolithic -build_sources_library level_0/account.c level_0/console.c level_0/conversion.c level_0/directory.c level_0/private-directory.c level_0/environment.c level_0/private-environment.c level_0/file.c level_0/private-file.c level_0/fss.c level_0/iki.c level_0/private-iki.c level_0/memory.c level_0/path.c level_0/private-path.c level_0/pipe.c level_0/print.c level_0/private-print.c level_0/serialize.c level_0/private-serialize.c level_0/signal.c level_0/socket.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/conversion.c level_1/directory.c level_1/private-directory.c level_1/environment.c level_1/private-fss.c level_1/fss_basic.c level_1/fss_basic_list.c level_1/fss_extended.c level_1/fss_extended_list.c level_1/iki.c level_1/print.c level_1/private-print.c level_1/status.c level_1/string.c level_1/private-string.c level_1/utf.c level_1/private-utf.c level_1/utf_file.c level_1/private-utf_file.c level_2/error.c level_2/private-error.c level_2/execute.c level_2/private-execute.c level_2/file.c level_2/private-file.c level_2/fss.c level_2/private-fss.c level_2/fss_basic.c level_2/fss_basic_list.c level_2/fss_extended.c level_2/fss_extended_list.c level_2/fss_status.c level_2/iki.c level_2/private-iki.c level_2/path.c level_2/program.c level_2/status.c +build_sources_library level_0/account.c level_0/console.c level_0/conversion.c level_0/directory.c level_0/private-directory.c level_0/environment.c level_0/private-environment.c level_0/file.c level_0/private-file.c level_0/fss.c level_0/iki.c level_0/private-iki.c level_0/memory.c level_0/path.c level_0/private-path.c level_0/pipe.c level_0/print.c level_0/private-print.c level_0/serialize.c level_0/private-serialize.c level_0/signal.c level_0/socket.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/conversion.c level_1/directory.c level_1/private-directory.c level_1/environment.c level_1/private-fss.c level_1/fss_basic.c level_1/fss_basic_list.c level_1/fss_embedded_list.c level_1/fss_extended.c level_1/fss_extended_list.c level_1/iki.c level_1/print.c level_1/private-print.c level_1/status.c level_1/string.c level_1/private-string.c level_1/utf.c level_1/private-utf.c level_1/utf_file.c level_1/private-utf_file.c level_2/error.c level_2/private-error.c level_2/execute.c level_2/private-execute.c level_2/file.c level_2/private-file.c level_2/fss.c level_2/private-fss.c level_2/fss_basic.c level_2/fss_basic_list.c level_2/fss_embedded_list.c level_2/fss_extended.c level_2/fss_extended_list.c level_2/fss_status.c level_2/iki.c level_2/private-iki.c level_2/path.c level_2/program.c level_2/status.c build_sources_program -build_sources_headers level_0/account.h level_0/account-common.h level_0/color.h level_0/console.h level_0/console-common.h level_0/conversion.h level_0/conversion-common.h level_0/directory.h level_0/directory_type.h level_0/directory-common.h level_0/environment.h level_0/environment-common.h level_0/file.h level_0/file-common.h level_0/fss.h level_0/fss-common.h level_0/fss_comment.h level_0/fss_delimit.h level_0/fss_named.h level_0/fss_nest.h level_0/fss_quote.h level_0/fss_set.h level_0/iki.h level_0/iki-common.h level_0/memory.h level_0/memory_structure.h level_0/path.h level_0/path-common.h level_0/pipe.h level_0/print.h level_0/serialize.h level_0/serialize-common.h level_0/signal.h level_0/signal-common.h level_0/socket.h level_0/socket-common.h level_0/status.h level_0/status_array.h level_0/string.h level_0/string-common.h level_0/string_dynamic.h level_0/string_map.h level_0/string_quantity.h level_0/string_range.h level_0/type.h level_0/type_array.h level_0/utf.h level_0/utf-common.h level_1/color.h level_1/console.h level_1/conversion.h level_1/directory.h level_1/environment.h level_1/fss.h level_1/fss_basic.h level_1/fss_basic_list.h level_1/fss_extended.h level_1/fss_extended_list.h level_1/fss_macro.h level_1/fss_status.h level_1/iki.h level_1/print.h level_1/status.h level_1/string.h level_1/utf.h level_1/utf_file.h level_2/error.h level_2/error-common.h level_2/execute.h level_2/file.h level_2/fss.h level_2/fss_basic.h level_2/fss_basic_list.h level_2/fss_extended.h level_2/fss_extended_list.h level_2/fss_status.h level_2/iki.h level_2/path.h level_2/program.h level_2/status.h +build_sources_headers level_0/account.h level_0/account-common.h level_0/color.h level_0/console.h level_0/console-common.h level_0/conversion.h level_0/conversion-common.h level_0/directory.h level_0/directory_type.h level_0/directory-common.h level_0/environment.h level_0/environment-common.h level_0/file.h level_0/file-common.h level_0/fss.h level_0/fss-common.h level_0/fss_comment.h level_0/fss_delimit.h level_0/fss_named.h level_0/fss_nest.h level_0/fss_quote.h level_0/fss_set.h level_0/iki.h level_0/iki-common.h level_0/memory.h level_0/memory_structure.h level_0/path.h level_0/path-common.h level_0/pipe.h level_0/print.h level_0/serialize.h level_0/serialize-common.h level_0/signal.h level_0/signal-common.h level_0/socket.h level_0/socket-common.h level_0/status.h level_0/status_array.h level_0/string.h level_0/string-common.h level_0/string_dynamic.h level_0/string_map.h level_0/string_quantity.h level_0/string_range.h level_0/type.h level_0/type_array.h level_0/utf.h level_0/utf-common.h level_1/color.h level_1/console.h level_1/conversion.h level_1/directory.h level_1/environment.h level_1/fss.h level_1/fss_basic.h level_1/fss_basic_list.h level_1/fss_embedded_list.h level_1/fss_extended.h level_1/fss_extended_list.h level_1/fss_macro.h level_1/fss_status.h level_1/iki.h level_1/print.h level_1/status.h level_1/string.h level_1/utf.h level_1/utf_file.h level_2/error.h level_2/error-common.h level_2/execute.h level_2/file.h level_2/fss.h level_2/fss_basic.h level_2/fss_basic_list.h level_2/fss_embedded_list.h level_2/fss_extended.h level_2/fss_extended_list.h level_2/fss_status.h level_2/iki.h level_2/path.h level_2/program.h level_2/status.h build_sources_script build_sources_setting build_script yes diff --git a/level_0/f_fss/c/fss-common.h b/level_0/f_fss/c/fss-common.h index b8129ad..bb30860 100644 --- a/level_0/f_fss/c/fss-common.h +++ b/level_0/f_fss/c/fss-common.h @@ -36,6 +36,10 @@ extern "C" { #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_embedded_list_open '{' + #define f_fss_embedded_list_open_end f_string_eol[0] + #define f_fss_embedded_list_close '}' + #define f_fss_embedded_list_close_end f_string_eol[0] #define f_fss_type_header_open '#' #define f_fss_type_header_part1 ' ' #define f_fss_type_header_part2 'f' @@ -73,8 +77,9 @@ extern "C" { f_fss_embeded_list, f_fss_reverse_mapping, f_fss_extended_reverse_mapping, - f_fss_simple_json, f_fss_simple_list, + f_fss_iki_text, + f_fss_basic_rule, }; #endif // _di_f_fss_codes_ diff --git a/level_1/fl_fss/c/fss_basic.h b/level_1/fl_fss/c/fss_basic.h index ef7146d..4070fd9 100644 --- a/level_1/fl_fss/c/fss_basic.h +++ b/level_1/fl_fss/c/fss_basic.h @@ -45,7 +45,7 @@ extern "C" { * The start location will represent where the read stopped on return. * A start location past the stop location or buffer used means that the entire range was processed. * @param found - * A set of all locations where a valid object was found. + * A location where a valid object was found. * @param quote * This will store whether or not this object is quote and what quote is in use. * Set pointer address to 0 to not use. diff --git a/level_1/fl_fss/c/fss_basic_list.h b/level_1/fl_fss/c/fss_basic_list.h index 16e3317..962711c 100644 --- a/level_1/fl_fss/c/fss_basic_list.h +++ b/level_1/fl_fss/c/fss_basic_list.h @@ -46,7 +46,7 @@ extern "C" { * The start location will represent where the read stopped on return. * A start location past the stop location or buffer used means that the entire range was processed. * @param found - * A set of all locations where a valid object was found. + * A location where a valid object was found. * @param delimits * A delimits array representing where delimits exist within the buffer. * diff --git a/level_1/fl_fss/c/fss_embedded_list.c b/level_1/fl_fss/c/fss_embedded_list.c new file mode 100644 index 0000000..51b629c --- /dev/null +++ b/level_1/fl_fss/c/fss_embedded_list.c @@ -0,0 +1,1300 @@ +#include "fss_embedded_list.h" +#include "private-fss.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fl_fss_embedded_list_object_read_ + f_return_status fl_fss_embedded_list_object_read(f_string_dynamic_t *buffer, f_string_range_t *range, f_fss_object_t *found, f_fss_delimits_t *delimits) { + #ifndef _di_level_1_parameter_checking_ + if (!buffer) return F_status_set_error(F_parameter); + if (!range) return F_status_set_error(F_parameter); + if (!found) return F_status_set_error(F_parameter); + if (!delimits) return F_status_set_error(F_parameter); + #endif // _di_level_1_parameter_checking_ + + const f_array_length_t delimits_used = delimits->used; + + f_status_t status = f_fss_skip_past_space(*buffer, range); + if (F_status_is_error(status)) return status; + + if (status == F_none_eol) { + + // move the start position to after the EOL. + range->start++; + + return FL_fss_found_object_not; + } + + if (status == F_none_eos) { + return F_data_not_eos; + } + + if (status == F_none_stop) { + return F_data_not_stop; + } + + // return found nothing if this line only contains whitespace and delimit placeholders. + if (buffer->string[range->start] == f_fss_eol) { + + // move the start position to after the EOL. + range->start++; + + return FL_fss_found_object_not; + } + + // begin the search. + found->start = range->start; + + // ignore all comment lines. + if (buffer->string[range->start] == f_fss_comment) { + status = f_fss_seek_to_eol(*buffer, range); + + if (F_status_is_error(status)) { + delimits->used = delimits_used; + return status; + } + + if (status == F_none_eos) { + return F_data_not_eos; + } + + if (status == F_none_stop) { + return F_data_not_stop; + } + + // move the start position to after the EOL. + range->start++; + + return FL_fss_found_object_not; + } + + f_string_length_t start = 0; + f_string_length_t stop = 0; + f_string_length_t slash_first = 0; + f_string_length_t slash_count = 0; + + bool graph_first = F_true; + + // identify where the object ends. + while (range->start <= range->stop && range->start < buffer->used && buffer->string[range->start] != f_fss_eol) { + + if (buffer->string[range->start] == f_fss_delimit_slash) { + slash_first = range->start; + slash_count = 1; + + status = f_utf_buffer_increment(*buffer, range, 1); + if (F_status_is_error(status)) break; + + while (range->start <= range->stop && range->start < buffer->used && (buffer->string[range->start] == f_fss_delimit_placeholder || buffer->string[range->start] == f_fss_delimit_slash)) { + + if (buffer->string[range->start] == f_fss_delimit_slash) slash_count++; + + status = f_utf_buffer_increment(*buffer, range, 1); + if (F_status_is_error(status)) break; + } // while + + if (F_status_is_error(status)) break; + + fl_macro_fss_object_return_on_overflow((*buffer), (*range), (*found), (*delimits), delimits_used, F_data_not_eos, F_data_not_stop); + + if (buffer->string[range->start] == f_fss_embedded_list_open) { + graph_first = F_false; + stop = range->start - 1; + range->start++; + + while (range->start <= range->stop && range->start < buffer->used) { + + if (buffer->string[range->start] == f_fss_eol) break; + + status = f_fss_is_graph(*buffer, *range); + if (F_status_is_error(status)) break; + + if (status == F_true) break; + + status = f_utf_buffer_increment(*buffer, range, 1); + if (F_status_is_error(status)) break; + } // while + + fl_macro_fss_object_return_on_overflow((*buffer), (*range), (*found), (*delimits), delimits_used, F_data_not_eos, F_data_not_stop); + + if (buffer->string[range->start] == f_fss_eol) { + start = range->start; + + range->start = slash_first; + + status = private_fl_fss_delimits_increase_by((slash_count / 2) + 1, delimits); + if (F_status_is_error(status)) break; + + if (slash_count % 2 == 0) { + while (slash_count > 0) { + + if (buffer->string[range->start] == f_fss_delimit_slash) { + if (slash_count % 2 == 1) { + delimits->array[delimits->used] = range->start; + delimits->used++; + } + + slash_count--; + } + + status = f_utf_buffer_increment(*buffer, range, 1); + if (F_status_is_error(status)) break; + } // while + + if (F_status_is_error(status)) break; + + found->stop = stop; + range->start = start + 1; + + return FL_fss_found_object; + } + + range->start = start + 1; + return FL_fss_found_object_not; + } + } + else if (graph_first && buffer->string[range->start] == f_fss_comment) { + graph_first = F_false; + + // comments may only have whitespace before the '#', therefore only the first slash needs to be delimited. + status = private_fl_fss_delimits_increase(delimits); + if (F_status_is_error(status)) break; + + delimits->array[delimits->used++] = slash_first; + range->start++; + } + else { + graph_first = F_false; + } + + continue; + } + else if (buffer->string[range->start] == f_fss_embedded_list_open) { + graph_first = F_false; + stop = range->start - 1; + + status = f_utf_buffer_increment(*buffer, range, 1); + if (F_status_is_error(status)) break; + + while (range->start <= range->stop && range->start < buffer->used) { + + if (buffer->string[range->start] == f_fss_eol) break; + + status = f_fss_is_space(*buffer, *range); + if (F_status_is_error(status)) break; + + if (status == F_false) break; + + status = f_utf_buffer_increment(*buffer, range, 1); + if (F_status_is_error(status)) break; + } // while + + if (F_status_is_error(status)) break; + + fl_macro_fss_object_return_on_overflow_delimited((*buffer), (*range), (*found), F_none_eos, F_none_stop); + + if (buffer->string[range->start] == f_fss_eol) { + found->stop = stop; + + // move the start position to after the EOL. + range->start++; + + return FL_fss_found_object; + } + + continue; + } + else if (graph_first) { + status = f_fss_is_space(*buffer, *range); + if (F_status_is_error(status)) break; + + if (status == F_false) { + graph_first = F_false; + } + } + + status = f_utf_buffer_increment(*buffer, range, 1); + if (F_status_is_error(status)) break; + } // while + + if (F_status_is_error(status)) { + delimits->used = delimits_used; + return status; + } + + // seek to the end of the line when no valid object is found. + while (range->start <= range->stop && range->start < buffer->used && buffer->string[range->start] != f_fss_eol) { + + status = f_utf_buffer_increment(*buffer, range, 1); + + if (F_status_is_error(status)) { + delimits->used = delimits_used; + return status; + } + } // while + + fl_macro_fss_object_return_on_overflow((*buffer), (*range), (*found), (*delimits), delimits_used, F_data_not_eos, F_data_not_stop); + + status = f_utf_buffer_increment(*buffer, range, 1); + + if (F_status_is_error(status)) { + delimits->used = delimits_used; + return status; + } + + return FL_fss_found_object_not; + } +#endif // _di_fl_fss_embedded_list_object_read_ + +#ifndef _di_fl_fss_embedded_list_content_read_ + f_return_status fl_fss_embedded_list_content_read(f_string_dynamic_t *buffer, f_string_range_t *range, f_fss_nest_t *found, f_fss_delimits_t *delimits, f_fss_comments_t *comments) { + #ifndef _di_level_1_parameter_checking_ + if (!buffer) return F_status_set_error(F_parameter); + if (!range) return F_status_set_error(F_parameter); + if (!found) return F_status_set_error(F_parameter); + if (!delimits) return F_status_set_error(F_parameter); + if (!comments) return F_status_set_error(F_parameter); + #endif // _di_level_1_parameter_checking_ + + const f_array_length_t found_used = found->used; + + f_status_t status = f_fss_skip_past_delimit(*buffer, range); + if (F_status_is_error(status)) return status; + + if (status == F_none_eos || status == F_none_stop) { + return status; + } + + status = private_fl_fss_nest_increase(found); + if (F_status_is_error(status)) return status; + + f_string_lengths_t positions_start = f_string_lengths_t_initialize; + + f_macro_string_lengths_t_new(status, positions_start, f_fss_default_allocation_step); + if (F_status_is_error(status)) return status; + + f_fss_objects_t objects = f_fss_objects_t_initialize; + + f_macro_fss_objects_t_new(status, objects, f_fss_default_allocation_step); + + if (F_status_is_error(status)) { + f_macro_string_lengths_t_delete_simple(positions_start); + + return status; + } + + const f_array_length_t delimits_used = delimits->used; + const f_array_length_t comments_used = comments->used; + + f_array_length_t depth = 0; + f_array_length_t position = 0; + + f_string_length_t position_previous = range->start; + f_string_length_t line_start = range->start; + f_string_length_t newline_last = range->start; + f_string_length_t comment_delimit = 0; + + f_string_length_t slash_first = 0; + f_string_length_t slash_last = 0; + f_string_length_t slash_count = 0; + + f_string_length_t before_list_open = position_previous; + + bool is_open = F_false; + + uint8_t graph_first = 0x0; // 0x0 = false, 0x1 = true, 0x2 = false, but there is a delimited comment, comment_delimit is set. + + // initialize depth 1 start position. + // positions_start.used is used as a max depth (such that positions_start.used == max depth + 1). + positions_start.array[0] = range->start; + positions_start.used = 1; + + while (range->start <= range->stop && range->start < buffer->used) { + + if (buffer->string[range->start] == f_fss_eol) { + if (graph_first == 0x2) { + status = private_fl_fss_delimits_increase(delimits); + if (F_status_is_error(status)) break; + + delimits->array[delimits->used++] = comment_delimit; + } + + newline_last = range->start; + position_previous = range->start++; + graph_first = 0x1; + + if (depth > 0) { + fl_macro_fss_nest_return_on_overflow((*buffer), (*range), (*found), (*delimits), delimits_used, (*comments), comments_used, positions_start, objects, F_unterminated_nest_eos, F_unterminated_nest_stop); + } + else { + fl_macro_fss_nest_return_on_overflow_delimited((*buffer), (*range), (*found), positions_start, objects, F_none_eos, F_none_stop); + } + + line_start = range->start; + continue; + } + + if (buffer->string[range->start] == f_fss_delimit_slash) { + slash_first = range->start; + slash_last = range->start; + slash_count = 1; + + position_previous = range->start; + + status = f_utf_buffer_increment(*buffer, range, 1); + if (F_status_is_error(status)) break; + + while (range->start <= range->stop && range->start < buffer->used && (buffer->string[range->start] == f_fss_delimit_placeholder || buffer->string[range->start] == f_fss_delimit_slash)) { + position_previous = range->start; + + if (buffer->string[range->start] == f_fss_delimit_slash) { + slash_last = range->start++; + } + + status = f_utf_buffer_increment(*buffer, range, 1); + if (F_status_is_error(status)) break; + } // while + + if (F_status_is_error(status)) break; + + if (depth > 0) { + fl_macro_fss_nest_return_on_overflow((*buffer), (*range), (*found), (*delimits), delimits_used, (*comments), comments_used, positions_start, objects, F_unterminated_nest_eos, F_unterminated_nest_stop); + } + else { + fl_macro_fss_nest_return_on_overflow((*buffer), (*range), (*found), (*delimits), delimits_used, (*comments), comments_used, positions_start, objects, F_data_not_eos, F_data_not_stop); + } + + // All slashes for an open are delimited (because it could represent a slash in the object name). + // for example 'object {' = valid open, name 'object', 'object \{' represents 'object {', 'object \\{' = valid open, name 'object \', 'object \\\{' represents 'object \{', etc.. + // Only the first slash before a close is delimited, all others are maintained. + // for example '}' = valid close, '\}' represents '}', '\\}' represents '\}', '\\\}' represents '\\}', '\\\\}' represents '\\\}', and so on.. + // When slash is odd and a (delimited) valid open/close is found, then save delimited positions and continue. + if (buffer->string[range->start] == f_fss_eol) { + if (graph_first == 0x2) { + status = private_fl_fss_delimits_increase(delimits); + if (F_status_is_error(status)) break; + + delimits->array[delimits->used++] = comment_delimit; + } + + newline_last = range->start; + position_previous = range->start++; + line_start = range->start; + graph_first = 0x1; + } + else if (buffer->string[range->start] == f_fss_embedded_list_open || buffer->string[range->start] == f_fss_embedded_list_close) { + before_list_open = position_previous; + is_open = F_false; + graph_first = 0x0; + + if (buffer->string[range->start] == f_fss_embedded_list_open) { + is_open = F_true; + } + + position_previous = range->start++; + + while (range->start <= range->stop && range->start < buffer->used) { + + if (buffer->string[range->start] == f_fss_eol) { + if (graph_first == 0x2) { + status = private_fl_fss_delimits_increase(delimits); + if (F_status_is_error(status)) break; + + delimits->array[delimits->used++] = comment_delimit; + } + + newline_last = range->start; + line_start = range->start + 1; + graph_first = 0x1; + break; + } + + if (buffer->string[range->start] != f_fss_delimit_placeholder) { + status = f_fss_is_space(*buffer, *range); + if (F_status_is_error(status)) break; + + if (status == F_false) break; + } + + position_previous = range->start; + + status = f_utf_buffer_increment(*buffer, range, 1); + if (F_status_is_error(status)) break; + } // while + + if (F_status_is_error(status)) break; + + if (depth > 0) { + fl_macro_fss_nest_return_on_overflow((*buffer), (*range), (*found), (*delimits), delimits_used, (*comments), comments_used, positions_start, objects, F_unterminated_nest_eos, F_unterminated_nest_stop); + } + else { + fl_macro_fss_nest_return_on_overflow((*buffer), (*range), (*found), (*delimits), delimits_used, (*comments), comments_used, positions_start, objects, F_data_not_eos, F_data_not_stop); + } + + // this is a valid object open/close that has been delimited, save the slash delimit positions. + if (buffer->string[range->start] == f_fss_eol) { + newline_last = range->start; + line_start = range->start + 1; + graph_first = 0x1; + + if (is_open) { + bool is_object = F_false; + + if (slash_count % 2 == 0) { + is_object = F_true; + } + + range->start = slash_first; + + status = private_fl_fss_delimits_increase_by((slash_count / 2) + 1, delimits); + if (F_status_is_error(status)) break; + + // apply slash delimits, only slashes and placeholders should be present. + while (slash_count > 0) { + + if (buffer->string[range->start] == f_fss_delimit_slash) { + if (slash_count % 2 == 1) { + delimits->array[delimits->used++] = range->start; + } + + slash_count--; + } + + // Delimit slashes and placeholders are required to be in the ASCII range. + position_previous = range->start++; + } // while + + if (F_status_is_error(status)) break; + + // when slashes are even, the object is valid and needs to be processed. + if (is_object) { + depth++; + + if (depth > positions_start.size) { + f_macro_string_lengths_t_resize(status, positions_start, positions_start.size + f_fss_default_allocation_step); + if (F_status_is_error(status)) break; + } + + if (positions_start.used < depth) { + positions_start.used = depth; + } + + positions_start.array[depth] = newline_last + 1; + + objects.array[depth].start = line_start; + objects.array[depth].stop = before_list_open; + } + } + else { + status = private_fl_fss_delimits_increase(delimits); + if (F_status_is_error(status)) break; + + delimits->array[delimits->used++] = slash_last; + } + + range->start = newline_last; + } + } + else if (graph_first == 0x1 && buffer->string[range->start] == f_fss_comment) { + graph_first = 0x2; + comment_delimit = slash_first; + } + else { + graph_first = 0x0; + } + } + else if (buffer->string[range->start] == f_fss_embedded_list_open) { + graph_first = 0x0; + before_list_open = position_previous; + position_previous = range->start; + + status = f_utf_buffer_increment(*buffer, range, 1); + if (F_status_is_error(status)) break; + + while (range->start <= range->stop && range->start < buffer->used) { + + if (buffer->string[range->start] == f_fss_eol) break; + + if (buffer->string[range->start] != f_fss_delimit_placeholder) { + status = f_fss_is_space(*buffer, *range); + if (F_status_is_error(status)) break; + + if (status == F_false) break; + } + + position_previous = range->start; + + status = f_utf_buffer_increment(*buffer, range, 1); + if (F_status_is_error(status)) break; + } // while + + if (F_status_is_error(status)) break; + + if (depth > 0) { + fl_macro_fss_nest_return_on_overflow((*buffer), (*range), (*found), (*delimits), delimits_used, (*comments), comments_used, positions_start, objects, F_unterminated_nest_eos, F_unterminated_nest_stop); + } + else { + fl_macro_fss_nest_return_on_overflow((*buffer), (*range), (*found), (*delimits), delimits_used, (*comments), comments_used, positions_start, objects, F_data_not_eos, F_data_not_stop); + } + + if (buffer->string[range->start] == f_fss_eol) { + depth++; + + if (depth >= positions_start.size) { + f_macro_string_lengths_t_resize(status, positions_start, positions_start.size + f_fss_default_allocation_step); + if (F_status_is_error(status)) break; + + f_macro_fss_objects_t_resize(status, objects, objects.size + f_fss_default_allocation_step); + if (F_status_is_error(status)) break; + } + + if (positions_start.used <= depth) { + positions_start.used = depth + 1; + } + + positions_start.array[depth] = range->start + 1; + + objects.array[depth].start = line_start; + objects.array[depth].stop = before_list_open; + + if (graph_first == 0x2) { + status = private_fl_fss_delimits_increase(delimits); + if (F_status_is_error(status)) break; + + delimits->array[delimits->used++] = comment_delimit; + } + + newline_last = range->start; + line_start = range->start + 1; + graph_first = 0x1; + } + else { + + // No valid object close found, seek until EOL. + status = f_fss_seek_to_eol(*buffer, range); + if (F_status_is_error(status)) break; + + if (graph_first == 0x2) { + status = private_fl_fss_delimits_increase(delimits); + if (F_status_is_error(status)) break; + + delimits->array[delimits->used++] = comment_delimit; + } + + newline_last = range->start; + line_start = range->start + 1; + graph_first = 0x1; + + while (range->start <= range->stop && range->start < buffer->used) { + + if (buffer->string[range->start] == f_fss_eol) { + newline_last = range->start; + line_start = range->start + 1; + break; + } + + position_previous = range->start; + + status = f_utf_buffer_increment(*buffer, range, 1); + if (F_status_is_error(status)) break; + } // while + + if (F_status_is_error(status)) break; + + if (depth > 0) { + fl_macro_fss_nest_return_on_overflow((*buffer), (*range), (*found), (*delimits), delimits_used, (*comments), comments_used, positions_start, objects, F_unterminated_nest_eos, F_unterminated_nest_stop); + } + else { + fl_macro_fss_nest_return_on_overflow((*buffer), (*range), (*found), (*delimits), delimits_used, (*comments), comments_used, positions_start, objects, F_data_not_eos, F_data_not_stop); + } + } + } + else if (buffer->string[range->start] == f_fss_embedded_list_close) { + graph_first = 0x0; + + while (range->start <= range->stop && range->start < buffer->used) { + + position_previous = range->start; + + status = f_utf_buffer_increment(*buffer, range, 1); + if (F_status_is_error(status)) break; + + if (buffer->string[range->start] == f_fss_eol) { + break; + } + + if (buffer->string[range->start] != f_fss_delimit_placeholder) { + status = f_fss_is_space(*buffer, *range); + if (F_status_is_error(status)) break; + + if (status == F_false) { + break; + } + } + } // while + + if (F_status_is_error(status)) break; + + if (depth > 0) { + fl_macro_fss_nest_return_on_overflow((*buffer), (*range), (*found), (*delimits), delimits_used, (*comments), comments_used, positions_start, objects, F_unterminated_nest_eos, F_unterminated_nest_stop); + } + else { + fl_macro_fss_nest_return_on_overflow((*buffer), (*range), (*found), (*delimits), delimits_used, (*comments), comments_used, positions_start, objects, F_data_not_eos, F_data_not_stop); + } + + if (buffer->string[range->start] == f_fss_eol) { + status = private_fl_fss_nest_increase(found); + if (F_status_is_error(status)) break; + + if (found->depth[depth].used == found->depth[depth].size) { + f_macro_fss_items_t_resize(status, found->depth[depth], found->depth[depth].size + f_fss_default_allocation_step); + if (F_status_is_error(status)) break; + } + + position = found->depth[depth].used; + + if (found->depth[depth].array[position].content.size != 1) { + f_macro_fss_content_t_resize(status, found->depth[depth].array[position].content, 1); + if (F_status_is_error(status)) break; + } + + if (depth) { + found->depth[depth].array[position].parent = found->depth[depth - 1].used; + + // only assign object positions for nested objects. + found->depth[depth].array[position].object.start = objects.array[depth].start; + found->depth[depth].array[position].object.stop = objects.array[depth].stop; + } + + found->depth[depth].array[position].content.array[0].start = positions_start.array[depth]; + found->depth[depth].array[position].content.array[0].stop = newline_last; + found->depth[depth].array[position].content.used = 1; + + if (position >= found->depth[depth].used) { + found->depth[depth].used++; + } + + if (found->used < depth + 1) { + found->used = depth + 1; + } + + if (graph_first == 0x2) { + status = private_fl_fss_delimits_increase(delimits); + if (F_status_is_error(status)) break; + + delimits->array[delimits->used++] = comment_delimit; + } + + newline_last = range->start; + line_start = range->start + 1; + graph_first = 0x1; + + if (!depth) { + status = f_utf_buffer_increment(*buffer, range, 1); + if (F_status_is_error(status)) break; + + fl_macro_fss_nest_return_on_overflow_delimited((*buffer), (*range), (*found), positions_start, objects, F_none_eos, F_none_stop) + + f_macro_string_lengths_t_delete_simple(positions_start); + f_macro_fss_objects_t_delete_simple(objects); + + return FL_fss_found_content; + } + + depth--; + } + else { + + // No valid object close found, seek until EOL. + while (range->start <= range->stop && range->start < buffer->used) { + + if (buffer->string[range->start] == f_fss_eol) { + if (graph_first == 0x2) { + status = private_fl_fss_delimits_increase(delimits); + if (F_status_is_error(status)) break; + + delimits->array[delimits->used++] = comment_delimit; + } + + newline_last = range->start; + line_start = range->start + 1; + graph_first = 0x1; + break; + } + + position_previous = range->start; + + status = f_utf_buffer_increment(*buffer, range, 1); + if (F_status_is_error(status)) break; + } // while + + if (F_status_is_error(status)) break; + + if (depth > 0) { + fl_macro_fss_nest_return_on_overflow((*buffer), (*range), (*found), (*delimits), delimits_used, (*comments), comments_used, positions_start, objects, F_unterminated_nest_eos, F_unterminated_nest_stop) + } + else { + fl_macro_fss_nest_return_on_overflow((*buffer), (*range), (*found), (*delimits), delimits_used, (*comments), comments_used, positions_start, objects, F_data_not_eos, F_data_not_stop) + } + } + } + else if (graph_first == 0x1 && buffer->string[range->start] == f_fss_comment) { + position = range->start; + + status = f_fss_seek_to_eol(*buffer, range); + if (F_status_is_error(status)) break; + + status = private_fl_fss_ranges_increase(comments); + if (F_status_is_error(status)) break; + + if (range->start > range->stop || range->start >= buffer->used) { + range->start--; + } + else { + if (graph_first == 0x2) { + status = private_fl_fss_delimits_increase(delimits); + if (F_status_is_error(status)) break; + + delimits->array[delimits->used++] = comment_delimit; + } + + newline_last = range->start; + graph_first = 0x1; + } + + comments->array[comments->used].start = position; + comments->array[comments->used++].stop = range->start++; + continue; + } + else if (buffer->string[range->start] != f_fss_eol) { + position_previous = range->start; + + if (graph_first == 0x1) { + status = f_fss_is_space(*buffer, *range); + if (F_status_is_error(status)) break; + + if (status == F_false) { + graph_first = 0x0; + } + } + + status = f_utf_buffer_increment(*buffer, range, 1); + if (F_status_is_error(status)) break; + + if (range->start >= buffer->used || range->start > range->stop) { + break; + } + + continue; + } + + position_previous = range->start; + + status = f_utf_buffer_increment(*buffer, range, 1); + if (F_status_is_error(status)) break; + } // while + + f_macro_string_lengths_t_delete_simple(positions_start); + f_macro_fss_objects_t_delete_simple(objects); + + delimits->used = delimits_used; + comments->used = comments_used; + + if (F_status_is_error(status)) { + return status; + } + + if (range->start > range->stop) { + if (!depth) { + return F_status_set_error(F_unterminated_stop); + } + + return F_status_set_error(F_unterminated_nest_stop); + } + + if (!depth) { + return F_status_set_error(F_unterminated_eos); + } + + return F_status_set_error(F_unterminated_nest_eos); + } +#endif // _di_fl_fss_embedded_list_content_read_ + +#ifndef _di_fl_fss_embedded_list_object_write_string_ + f_return_status fl_fss_embedded_list_object_write_string(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_fss_skip_past_delimit(object, range); + if (F_status_is_error(status)) return status; + + if (status == F_none_eos) { + status = F_data_not_eos; + } + else if (status == F_none_stop) { + status = F_data_not_stop; + } + + if (status == F_data_not_stop || status == F_data_not_eos) { + if (complete == f_fss_complete_partial || complete == f_fss_complete_partial_trim || complete == f_fss_complete_full || complete == f_fss_complete_full_trim) { + const f_status_t status_allocation = private_fl_fss_destination_increase_by(2, destination); + if (F_status_is_error(status_allocation)) return status_allocation; + + destination->string[destination->used++] = f_fss_embedded_list_open; + + if (complete == f_fss_complete_full || complete == f_fss_complete_full_trim) { + destination->string[destination->used++] = f_fss_embedded_list_open_end; + } + } + + return status; + } + + // 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) { + + // 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; + } + + 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) { + 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)) 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) { + slash_count = 1; + + for (range->start++; range->start <= range->stop && range->start < object.used; range->start++) { + + if (object.string[range->start] == f_fss_delimit_placeholder) { + continue; + } else if (object.string[range->start] != f_fss_delimit_slash) { + break; + } + + slash_count++; + } // for + + if (F_status_is_error(status)) break; + + if (range->start > range->stop || range->start >= object.used) { + + // slashes at the end of the object must be delimited to avoid delimiting the object close character. + slash_count *= 2; + } + + status = private_fl_fss_destination_increase_by(slash_count, destination); + if (F_status_is_error(status)) break; + + 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; + } + } + + if (object.string[range->start] != f_fss_delimit_placeholder) { + if (object.string[range->start] == f_fss_eol) { + status = F_status_set_error(F_none_eol); + break; + } + + status = f_fss_is_space(object, *range); + if (F_status_is_error(status)) break; + + 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)) break; + } // while + + if (F_status_is_error(status)) { + destination->used = used_start; + return status; + } + + if (complete == f_fss_complete_partial || complete == f_fss_complete_partial_trim || complete == f_fss_complete_full || complete == f_fss_complete_full_trim) { + if (complete == f_fss_complete_full_trim) { + status = private_fl_fss_basic_list_write_object_trim(used_start, destination); + + if (F_status_is_error(status)) { + destination->used = used_start; + return status; + } + + // prevent a space from being added post-trimming. + ends_on_space = F_true; + } + + status = private_fl_fss_destination_increase_by(3, destination); + + 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_embedded_list_open; + + if (complete == f_fss_complete_full || complete == f_fss_complete_full_trim) { + destination->string[destination->used++] = f_fss_embedded_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_embedded_list_object_write_string_ + +#ifndef _di_fl_fss_embedded_list_content_write_string_ + f_return_status fl_fss_embedded_list_content_write_string(const f_string_static_t content, const uint8_t complete, const f_string_static_t *prepend, const f_string_ranges_t *ignore, 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_ + + f_status_t status = f_fss_skip_past_delimit(content, range); + if (F_status_is_error(status)) return status; + + if (status == F_none_eos) { + status = F_data_not_eos; + } + else if (status == F_none_stop) { + status = F_data_not_stop; + } + + if (range->start > range->stop || range->start >= content.used) { + if (complete == f_fss_complete_full || complete == f_fss_complete_full_trim || complete == f_fss_complete_end) { + const f_status_t status_allocation = private_fl_fss_destination_increase_by(2, destination); + if (F_status_is_error(status_allocation)) return status_allocation; + + destination->string[destination->used++] = f_fss_embedded_list_close; + destination->string[destination->used++] = f_fss_embedded_list_close_end; + } + + return status; + } + + // 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; + + f_array_length_t r = 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) { + 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]; + + for (range->start++; range->start <= range->stop && range->start < content.used; range->start++) { + + if (content.string[range->start] == f_fss_delimit_placeholder) continue; + if (content.string[range->start] != f_fss_delimit_slash) break; + + destination->string[destination->used++] = f_fss_delimit_slash; + slash_count++; + } // for + + if (content.string[range->start] == f_fss_embedded_list_open || content.string[range->start] == f_fss_embedded_list_close) { + start = range->start++; + + status = f_fss_skip_past_space(content, range); + if (F_status_is_error(status)) break; + + if (has_graph && content.string[range->start] == f_fss_embedded_list_close) { + // do nothing. + } + else if (content.string[range->start] == f_fss_eol || range->start >= content.used || range->start > range->stop) { + + if (content.string[range->start] == f_fss_eol) { + ends_on_eol = F_true; + } + else { + ends_on_eol = F_false; + } + + // 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[destination->used++] = f_fss_delimit_slash; + destination->string[destination->used++] = content.string[start]; + + range->start = start + 1; + + status = private_fl_fss_basic_list_write_add_until_end(content, range, destination); + if (F_status_is_error(status)) break; + + if (content.string[range->start] != f_fss_eol) { + has_graph = F_true; + } + + continue; + } + + // increase by character at "start" and possible newline. + status = private_fl_fss_destination_increase_by(2, destination); + if (F_status_is_error(status)) break; + + destination->string[destination->used++] = content.string[start]; + + 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; + } + + range->start = start + 1; + continue; + } + } + else if ((content.string[range->start] == f_fss_embedded_list_open || (!has_graph && content.string[range->start] == f_fss_embedded_list_close)) && !is_comment) { + start = range->start++; + + if (do_prepend) { + status = private_fl_fss_destination_prepend(prepend, destination); + if (F_status_is_error(status)) break; + + do_prepend = F_false; + } + + has_graph = F_true; + + status = f_fss_skip_past_space(content, range); + if (F_status_is_error(status)) break; + + 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; + ends_on_eol = F_true; + } + else { + ends_on_eol = F_false; + } + + if (ignore && ignore->used) { + + for (r = 0; r < ignore->used; r++) { + if (start >= ignore->array[r].start && start <= ignore->array[r].stop) break; + } // for + + if (r < ignore->used) { + status = private_fl_fss_destination_increase(destination); + if (F_status_is_error(status)) break; + + destination->string[destination->used++] = content.string[start]; + range->start = start + 1; + continue; + } + } + + // 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; + destination->string[destination->used++] = content.string[start]; + + range->start = start + 1; + + status = private_fl_fss_basic_list_write_add_until_end(content, range, destination); + if (F_status_is_error(status)) break; + + continue; + } + + status = private_fl_fss_destination_increase(destination); + if (F_status_is_error(status)) break; + + destination->string[destination->used++] = content.string[start]; + 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_fss_eol) { + has_graph = F_false; + is_comment = F_false; + } + else if ((status = f_fss_is_graph(content, *range)) == F_true) { + has_graph = F_true; + } + else if (F_status_is_error(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; + 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)) break; + } // while + + if (F_status_is_error(status)) { + destination->used = used_start; + return status; + } + + if (complete == f_fss_complete_full || complete == f_fss_complete_full_trim || 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_embedded_list_close; + destination->string[destination->used++] = f_fss_embedded_list_close_end; + } + + if (range->start > range->stop) { + return F_none_stop; + } + + if (range->start >= content.used) { + return F_none_eos; + } + + return F_none; + } +#endif // _di_fl_fss_embedded_list_content_write_string_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_1/fl_fss/c/fss_embedded_list.h b/level_1/fl_fss/c/fss_embedded_list.h new file mode 100644 index 0000000..dc15a5c --- /dev/null +++ b/level_1/fl_fss/c/fss_embedded_list.h @@ -0,0 +1,225 @@ +/** + * FLL - Level 1 + * + * Project: FSS + * API Version: 0.5 + * Licenses: lgplv2.1 + * + * This is the fss-0008 implementation. + */ +#ifndef _FL_fss_embedded_list_h +#define _FL_fss_embedded_list_h + +// libc includes +#include +#include + +// fll-0 includes +#include +#include +#include +#include +#include +#include + +// fll-1 includes +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Read an fss-0008 object. + * + * This will record where delimit placeholders exist but will not apply the delimits. + * + * @param buffer + * The buffer to read from. + * This will be updated with delimit placeholders as it is being processed. + * @param range + * The start/stop location within the buffer to be processed. + * The start location will be updated as the buffer is being processed. + * The start location will represent where the read stopped on return. + * A start location past the stop location or buffer used means that the entire range was processed. + * @param found + * A location where a valid object was found. + * @param delimits + * A delimits array representing where delimits exist within the buffer. + * + * @return + * FL_fss_found_object on success and object was found (start location is at end of object). + * FL_fss_found_object_not on success and no object was found (start location is after character designating this is not an object). + * F_none_eos on success after reaching the end of the buffer (a valid object is not yet confirmed). + * F_none_stop on success after reaching stopping point (a valid object is not yet confirmed). + * F_data_not_eos no objects found after reaching the end of the buffer (essentially only comments are found). + * F_data_not_stop no data found after reaching stopping point (essentially only comments are found). + * F_unterminated_group_eos if EOS was reached before the a group termination was reached. + * F_unterminated_group_stop if stop point was reached before the a group termination was reached. + * F_array_too_large (with error bit) if a buffer is too large. + * 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_incomplete_utf_eos (with error bit) if the end of buffer is reached before the complete UTF-8 character can be processed. + * F_incomplete_utf_stop (with error bit) if the stop location is reached before the complete UTF-8 character can be processed. + * F_memory_reallocation (with error bit) on reallocation error. + * 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(). + * Errors (with error bit) from: f_fss_is_graph(). + * Errors (with error bit) from: f_fss_is_space(). + * Errors (with error bit) from: f_fss_seek_to_eol(). + * Errors (with error bit) from: f_fss_skip_past_space(). + */ +#ifndef _di_fl_fss_embedded_list_object_read_ + extern f_return_status fl_fss_embedded_list_object_read(f_string_dynamic_t *buffer, f_string_range_t *range, f_fss_object_t *found, f_fss_delimits_t *delimits); +#endif // _di_fl_fss_embedded_list_object_read_ + +/** + * Read an fss-0008 content. + * + * @fixme the recursive part of this is actually fss-0008 (Embedded) content, fss-0008 is not recursive, oops! + * + * This will record where delimit placeholders exist but will not apply the delimits. + * + * This operates on the assumption that found.array[0].array[found.array[0].used].content is the current content being processed. + * Therefore the object for this content will also need to be found.array[0].array[found.array[0].used].object. + * The object at depth 0 will not be populated, but all nested objects will be populated at their respective depth along with the content. + * + * @param buffer + * The buffer to read from. + * This will be updated with delimit placeholders as it is being processed. + * @param range + * The start/stop location within the buffer to be processed. + * The start location will be updated as the buffer is being processed. + * The start location will represent where the read stopped on return. + * A start location past the stop location or buffer used means that the entire range was processed. + * @param found + * A set of all locations where a valid content was found. + * @param delimits + * A delimits array representing where delimits exist within the buffer. + * @param comments + * An array of ranges representing where comments are found within any valid content. + * This only stores comments found within valid content only. + * The comment range will include the trailing newline. + * + * @return + * FL_fss_found_content on success and content was found (start location is at end of content). + * FL_fss_found_content_not on success and no content was found (start location is after character designating this is not a content). + * F_none_eos on success after reaching the end of the buffer (a valid object is not yet confirmed). + * F_none_stop on success after reaching stopping point (a valid object is not yet confirmed). + * F_data_not_eos no objects found after reaching the end of the buffer (essentially only comments are found). + * F_data_not_stop no data found after reaching stopping point (essentially only comments are found). + * F_unterminated_group_eos if EOS was reached before the a group termination was reached. + * F_unterminated_group_stop if stop point was reached before the a group termination was reached. + * F_array_too_large (with error bit) if a buffer is too large. + * 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_incomplete_utf_eos (with error bit) if the end of buffer is reached before the complete UTF-8 character can be processed. + * F_incomplete_utf_stop (with error bit) if the stop location is reached before the complete UTF-8 character can be processed. + * F_memory_reallocation (with error bit) on reallocation error. + * 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(). + * Errors (with error bit) from: f_fss_is_graph(). + * Errors (with error bit) from: f_fss_is_space(). + * Errors (with error bit) from: f_fss_skip_past_space(). + */ +#ifndef _di_fl_fss_embedded_list_content_read_ + extern f_return_status fl_fss_embedded_list_content_read(f_string_dynamic_t *buffer, f_string_range_t *range, f_fss_nest_t *found, f_fss_delimits_t *delimits, f_fss_comments_t *comments); +#endif // _di_fl_fss_embedded_list_content_read_ + +/** + * Write an fss-0008 object from a given string. + * + * This will write the given string range as a valid object. + * Anything within this range will be escaped as necessary. + * This will stop if EOL is reached. + * + * The destination string may have NULLs. + * + * @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_full, this will write any appropriate open and close aspects of this object. + * If f_fss_complete_full_trim, this will write any appropriate open and close aspects of this object, but will omit whitespace before and after the object. + * If f_fss_complete_partial, this will write any appropriate open and close aspects of this object. + * If f_fss_complete_partial_tim, this will write any appropriate open and close aspects of this object, but will omit whitespace before and after the object. + * @param range + * The start/stop location within the object string to write as an object. + * @param destination + * The buffer where the object is written to. + * + * @return + * F_none on success. + * F_none_eos on success after reaching the end of the buffer. + * F_data_not_stop no data to write due start location being greater than stop location. + * F_data_not_eos no data to write due start location being greater than or equal to buffer size. + * 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_embedded_list_object_write_string_ + extern f_return_status fl_fss_embedded_list_object_write_string(const f_string_static_t object, const uint8_t complete, f_string_range_t *range, f_string_dynamic_t *destination); +#endif // _di_fl_fss_embedded_list_object_write_string_ + +/** + * Write an fss-0008 content from a given string. + * + * This will write the given string range as a valid content. + * Anything within this range will be escaped as necessary. + * + * The destination string may have NULLs. + * + * @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 the pointer address to 0 to disable. + * @param ignore + * An optional list of ranges within the string to ignore. + * These ranges are only checked/ignored if there is a valid nested object open or a valid nested object close. + * Any valid nested object open or valid nested object close inside an ingore range will not be escaped. + * Set the pointer address to 0 to disable. + * @param range + * The start/stop location within the content string to write as an content. + * @param destination + * The buffer where the content is written to. + * + * @return + * F_none on success. + * F_none_eos on success after reaching the end of the buffer. + * F_data_not_stop no data to write due start location being greater than stop location. + * F_data_not_eos no data to write due start location being greater than or equal to buffer size. + * 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_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_embedded_list_content_write_string_ + extern f_return_status fl_fss_embedded_list_content_write_string(const f_string_static_t content, const uint8_t complete, const f_string_static_t *prepend, const f_string_ranges_t *ignore, f_string_range_t *range, f_string_dynamic_t *destination); +#endif // _di_fl_fss_embedded_list_content_write_string_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FL_fss_embedded_list_h diff --git a/level_1/fl_fss/c/fss_extended.h b/level_1/fl_fss/c/fss_extended.h index 7285c2f..7f1e3d2 100644 --- a/level_1/fl_fss/c/fss_extended.h +++ b/level_1/fl_fss/c/fss_extended.h @@ -45,7 +45,7 @@ extern "C" { * The start location will represent where the read stopped on return. * A start location past the stop location or buffer used means that the entire range was processed. * @param found - * A set of all locations where a valid object was found. + * A location where a valid object was found. * @param quoted * This will store whether or not this object is quoted and what quote is in use. * Set pointer address to 0 to not use. diff --git a/level_1/fl_fss/c/fss_extended_list.h b/level_1/fl_fss/c/fss_extended_list.h index e5a1358..d21f569 100644 --- a/level_1/fl_fss/c/fss_extended_list.h +++ b/level_1/fl_fss/c/fss_extended_list.h @@ -46,7 +46,7 @@ extern "C" { * The start location will represent where the read stopped on return. * A start location past the stop location or buffer used means that the entire range was processed. * @param found - * A set of all locations where a valid object was found. + * A location where a valid object was found. * @param delimits * A delimits array representing where delimits exist within the buffer. * @@ -80,6 +80,8 @@ extern "C" { /** * Read an fss-0003 content. * + * @fixme the recursive part of this is actually fss-0008 (Embedded) content, fss-0003 is not recursive, oops! + * * This will record where delimit placeholders exist but will not apply the delimits. * * This operates on the assumption that found.array[0].array[found.array[0].used].content is the current content being processed. diff --git a/level_1/fl_fss/data/build/settings b/level_1/fl_fss/data/build/settings index 3910c90..1bcef40 100644 --- a/level_1/fl_fss/data/build/settings +++ b/level_1/fl_fss/data/build/settings @@ -20,9 +20,9 @@ build_indexer ar build_language c build_libraries -lc build_libraries-individual -lf_file -lf_fss -lf_memory -lf_utf -build_sources_library private-fss.c fss_basic.c fss_basic_list.c fss_extended.c fss_extended_list.c +build_sources_library private-fss.c fss_basic.c fss_basic_list.c fss_embedded_list.c fss_extended.c fss_extended_list.c build_sources_program -build_sources_headers fss.h fss_basic.h fss_basic_list.h fss_extended.h fss_extended_list.h fss_macro.h fss_status.h +build_sources_headers fss.h fss_basic.h fss_basic_list.h fss_embedded_list.h fss_extended.h fss_extended_list.h fss_macro.h fss_status.h build_sources_script build_sources_setting build_script yes diff --git a/level_2/fll_fss/c/fss_embedded_list.c b/level_2/fll_fss/c/fss_embedded_list.c new file mode 100644 index 0000000..39b7bf2 --- /dev/null +++ b/level_2/fll_fss/c/fss_embedded_list.c @@ -0,0 +1,151 @@ +#include "fss_embedded_list.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fll_fss_embedded_list_read_ + f_return_status fll_fss_embedded_list_read(f_string_dynamic_t *buffer, f_string_range_t *range, f_fss_nest_t *nest, f_fss_delimits_t *objects_delimits, f_fss_delimits_t *contents_delimits, f_fss_comments_t *comments) { + #ifndef _di_level_3_parameter_checking_ + if (!buffer) return F_status_set_error(F_parameter); + if (!range) return F_status_set_error(F_parameter); + if (!nest) return F_status_set_error(F_parameter); + if (!objects_delimits) return F_status_set_error(F_parameter); + if (!comments) return F_status_set_error(F_parameter); + #endif // _di_level_3_parameter_checking_ + + f_status_t status = F_none; + f_status_t status2 = F_none; + f_string_length_t initial_used = 0; + + bool found_data = F_false; + + if (!nest->used) { + f_macro_fss_nest_t_resize(status2, (*nest), f_fss_default_allocation_step); + if (F_status_is_error(status2)) return status2; + } + else { + initial_used = nest->depth[0].used; + } + + do { + do { + if (nest->depth[0].used == nest->depth[0].size) { + f_macro_fss_items_t_resize(status2, nest->depth[0], nest->depth[0].used + f_fss_default_allocation_step); + if (F_status_is_error(status)) return status; + } + + status = fl_fss_embedded_list_object_read(buffer, range, &nest->depth[0].array[nest->depth[0].used].object, objects_delimits); + if (F_status_is_error(status)) return status; + + if (range->start >= range->stop || range->start >= buffer->used) { + if (status == FL_fss_found_object || status == FL_fss_found_object_content_not) { + + // extended list requires content closure, so this could be an error. + return FL_fss_found_object_content_not; + } + + if (found_data) { + if (range->start >= buffer->used) { + return F_none_eos; + } + + return F_none_stop; + } + else { + if (range->start >= buffer->used) { + return F_data_not_eos; + } + + return F_data_not_stop; + } + } + + if (status == FL_fss_found_object) { + found_data = F_true; + + status = fl_fss_embedded_list_content_read(buffer, range, nest, contents_delimits ? contents_delimits : objects_delimits, comments); + + break; + } + else if (status == FL_fss_found_object_content_not) { + found_data = F_true; + break; + } + } while (status == FL_fss_found_object_not); + + if (status == F_none_eos || status == F_none_stop) { + return status; + } + else if (status == F_data_not_eos || status == F_data_not_stop) { + + // If at least some valid object was found, then return F_none equivalents. + if (nest->depth[0].used > initial_used) { + if (status == F_data_not_eos) return F_none_eos; + if (status == F_data_not_stop) return F_none_stop; + } + + return status; + } + else if (status == F_unterminated_eos || status == F_unterminated_stop || status == F_unterminated_nest_eos || status == F_unterminated_nest_stop) { + + // If at least some valid object was found, then return F_none equivalents. + if (nest->depth[0].used > initial_used) { + if (status == F_data_not_eos) return F_none_eos; + if (status == F_data_not_stop) return F_none_stop; + } + + return status; + } + else if (status != FL_fss_found_object && status != FL_fss_found_content && status != FL_fss_found_content_not && status != FL_fss_found_object_content_not) { + return status; + } + // When content is found, the range->start is incremented, if content is found at range->stop, then range->start will be > range.stop. + else if (range->start >= range->stop || range->start >= buffer->used) { + if (range->start >= buffer->used) { + return F_none_eos; + } + + return F_none_stop; + } + } while (range->start < f_string_length_t_size); + + return F_status_is_error(F_number_overflow); + } +#endif // _di_fll_fss_embedded_list_read_ + +#ifndef _di_fll_fss_embedded_list_write_string_ + f_return_status fll_fss_embedded_list_write_string(const f_string_static_t object, const f_string_static_t content, const f_string_static_t *content_prepend, const f_string_ranges_t *ignore, 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_ + + f_status_t status = 0; + f_string_range_t range = f_macro_string_range_t_initialize(object.used); + + status = fl_fss_embedded_list_object_write_string(object, f_fss_complete_full, &range, destination); + + if (F_status_is_error(status) || status == F_data_not_stop || status == F_data_not_eos) { + return status; + } + + if (status == F_none || status == F_none_stop || status == F_none_eos || status == F_none_eol) { + if (content.used) { + range.start = 0; + range.stop = content.used - 1; + } + else { + range.start = 1; + range.stop = 0; + } + + status = fl_fss_embedded_list_content_write_string(content, f_fss_complete_full, content_prepend, ignore, &range, destination); + } + + return status; + } +#endif // _di_fll_fss_embedded_list_write_string_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_2/fll_fss/c/fss_embedded_list.h b/level_2/fll_fss/c/fss_embedded_list.h new file mode 100644 index 0000000..c5351f0 --- /dev/null +++ b/level_2/fll_fss/c/fss_embedded_list.h @@ -0,0 +1,118 @@ +/** + * FLL - Level 2 + * + * Project: FSS + * API Version: 0.5 + * Licenses: lgplv2.1 + * + * This is the fss-0008 implementation. + */ +#ifndef _FLL_fss_embedded_list_h +#define _FLL_fss_embedded_list_h + +// fll-0 includes +#include +#include +#include +#include +#include + +// fll-1 includes +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Read a buffer expected to be in fss-0008 format, getting all objects and their respective content. + * + * @param buffer + * The buffer to read from. + * @param range + * The range within the buffer that is currently being read. + * @param nest + * An nested set of all objects and content. + * @param objects_delimits + * An array of delimits for objects detected during processing. + * The caller is expected to decide if and when to process them. + * @param contents_delimits + * (optional) An array of delimits for contents detected during processing. + * The caller is expected to decide if and when to process them. + * Set pointer address to 0 and all delimits will instead utilize objects_delimits. + * @param comments + * An array of ranges representing where comments are found within any valid content. + * This only stores comments found within valid content only. + * + * @return + * F_none on success (both valid object and valid content found with start location is at end of content). + * F_none_eos on success after reaching the end of the buffer (both valid object and valid content found with start location is at end of buffer). + * F_none_stop on success after reaching stopping point (both valid object and valid content found with start location is at stop point). + * F_data_not_eol if there is no data to write and EOL was reached (@todo: review related code and detemine what this is doing). + * F_data_not_eos no data to write due start location being greater than or equal to buffer size. + * F_data_not_stop no data to write due start location being greater than stop location. + * 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_incomplete_utf_eos (with error bit) if the end of buffer is reached before the complete UTF-8 character can be processed. + * F_incomplete_utf_stop (with error bit) if the stop location is reached before the complete UTF-8 character can be processed. + * F_memory_reallocation (with error bit) on reallocation error. + * F_number_overflow (with error bit) if the maximimum buffer size is reached. + * F_parameter (with error bit) if a parameter is invalid. + * F_unterminated_eos (with error bit) if end of buffer is reached before a closing bracket is found (object was found). + * F_unterminated_nest_eos (with error bit) if end of buffer is reached while inside a nested list before a closing bracket is found (object was found). + * F_unterminated_nest_stop (with error bit) if stop location is reached while inside a nested list before a closing bracket is found (object was found). + * F_unterminated_stop (with error bit) if stop location is reached before a closing bracket is found (object was found). + * F_utf (with error bit) is returned on failure to read/process a UTF-8 character. + * FL_fss_found_object_content_not on success and object was found but no content was found (start location is at end of object). + * + * Errors (with error bit) from: fl_fss_embedded_list_content_read(). + * Errors (with error bit) from: fl_fss_embedded_list_object_read(). + */ +#ifndef _di_fll_fss_embedded_list_read_ + extern f_return_status fll_fss_embedded_list_read(f_string_dynamic_t *buffer, f_string_range_t *range, f_fss_nest_t *nest, f_fss_delimits_t *objects_delimits, f_fss_delimits_t *contents_delimits, f_fss_comments_t *comments); +#endif // _di_fll_fss_embedded_list_read_ + +/** + * Write a single object string and content string to a buffer, using fss-0008 format. + * + * @param object + * A string representing the object. + * @param content + * A string representing the content. + * @param content_prepend + * A string to prepend at the start of each line in content, such as spaces. + * Set the pointer address to 0 to disable. + * @param ignore + * An optional list of ranges within the string to ignore. + * These ranges are only checked/ignored if there is a valid nested object open or a valid nested object close. + * Any valid nested object open or valid nested object close inside an ingore range will not be escaped. + * Set the pointer address to 0 to disable. + * @param destination + * The buffer where the content is written to. + * + * @return + * F_none on success. + * F_none_eos on success after reaching the end of the buffer. + * F_none_stop on success after reaching stopping point. + * F_data_not_eos no data to write due start location being greater than or equal to buffer size. + * F_data_not_stop no data to write due start location being greater than stop location. + * 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_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: fl_fss_embedded_list_content_write_string(). + * Errors (with error bit) from: fl_fss_embedded_list_object_write_string(). + * Errors (with error bit) from: fl_string_dynamic_increase_by(). + */ +#ifndef _di_fll_fss_embedded_list_write_string_ + extern f_return_status fll_fss_embedded_list_write_string(const f_string_static_t object, const f_string_static_t content, const f_string_static_t *content_prepend, const f_string_ranges_t *ignore, f_string_dynamic_t *destination); +#endif // _di_fll_fss_embedded_list_write_string_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FLL_fss_embedded_list_h diff --git a/level_2/fll_fss/data/build/settings b/level_2/fll_fss/data/build/settings index c98f4e2..660ddf4 100644 --- a/level_2/fll_fss/data/build/settings +++ b/level_2/fll_fss/data/build/settings @@ -20,9 +20,9 @@ build_indexer ar build_language c build_libraries -lc build_libraries-individual -lfl_conversion -lfl_fss -lfl_status -lfl_string -lf_conversion -lf_file -lf_fss -lf_memory -lf_utf -build_sources_library fss.c private-fss.c fss_basic.c fss_basic_list.c fss_extended.c fss_extended_list.c fss_status.c +build_sources_library fss.c private-fss.c fss_basic.c fss_basic_list.c fss_embedded_list.c fss_extended.c fss_extended_list.c fss_status.c build_sources_program -build_sources_headers fss.h fss_basic.h fss_basic_list.h fss_extended.h fss_extended_list.h fss_status.h +build_sources_headers fss.h fss_basic.h fss_basic_list.h fss_embedded_list.h fss_extended.h fss_extended_list.h fss_status.h build_sources_script build_sources_setting build_script yes diff --git a/level_3/fss_embedded_list_read/c/fss_embedded_list_read.c b/level_3/fss_embedded_list_read/c/fss_embedded_list_read.c new file mode 100644 index 0000000..c625e52 --- /dev/null +++ b/level_3/fss_embedded_list_read/c/fss_embedded_list_read.c @@ -0,0 +1,529 @@ +#include "fss_embedded_list_read.h" +#include "private-fss_embedded_list_read.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fss_embedded_list_read_print_help_ + f_return_status fss_embedded_list_read_print_help(const f_file_t output, const f_color_context_t context) { + + fll_program_print_help_header(output, context, fss_embedded_list_read_name_long, fss_embedded_list_read_version); + + fll_program_print_help_option(output, 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(output, 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(output, 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(output, 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(output, 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(output, 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(output, 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(output, 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(output, 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."); + + fprintf(output.stream, "%c", f_string_eol[0]); + + fll_program_print_help_option(output, context, fss_embedded_list_read_short_at, fss_embedded_list_read_long_at, f_console_symbol_short_enable, f_console_symbol_long_enable, " Select object at this numeric index."); + fll_program_print_help_option(output, context, fss_embedded_list_read_short_content, fss_embedded_list_read_long_content, f_console_symbol_short_enable, f_console_symbol_long_enable, " Print the content (default)."); + fll_program_print_help_option(output, context, fss_embedded_list_read_short_delimit, fss_embedded_list_read_long_delimit, f_console_symbol_short_enable, f_console_symbol_long_enable, " Designate how to handle applying delimits."); + fll_program_print_help_option(output, context, fss_embedded_list_read_short_depth, fss_embedded_list_read_long_depth, f_console_symbol_short_enable, f_console_symbol_long_enable, " Select object at this numeric depth."); + fll_program_print_help_option(output, context, fss_embedded_list_read_short_empty, fss_embedded_list_read_long_empty, f_console_symbol_short_enable, f_console_symbol_long_enable, " Include empty content when processing."); + fll_program_print_help_option(output, context, fss_embedded_list_read_short_line, fss_embedded_list_read_long_line, f_console_symbol_short_enable, f_console_symbol_long_enable, " Print only the content at the given line."); + fll_program_print_help_option(output, context, fss_embedded_list_read_short_name, fss_embedded_list_read_long_name, f_console_symbol_short_enable, f_console_symbol_long_enable, " Select object with this name."); + fll_program_print_help_option(output, context, fss_embedded_list_read_short_object, fss_embedded_list_read_long_object, f_console_symbol_short_enable, f_console_symbol_long_enable, " Print the object."); + fll_program_print_help_option(output, context, fss_embedded_list_read_short_pipe, fss_embedded_list_read_long_pipe, f_console_symbol_short_enable, f_console_symbol_long_enable, " Print using the special pipe format."); + fll_program_print_help_option(output, context, fss_embedded_list_read_short_select, fss_embedded_list_read_long_select, f_console_symbol_short_enable, f_console_symbol_long_enable, " Select sub-content at this index."); + fll_program_print_help_option(output, context, fss_embedded_list_read_short_total, fss_embedded_list_read_long_total, f_console_symbol_short_enable, f_console_symbol_long_enable, " Print the total number of lines."); + fll_program_print_help_option(output, context, fss_embedded_list_read_short_trim, fss_embedded_list_read_long_trim, f_console_symbol_short_enable, f_console_symbol_long_enable, " Trim object names on select or print."); + + fll_program_print_help_usage(output, context, fss_embedded_list_read_name, "filename(s)"); + + fl_color_print(output.stream, context.set.important, " Notes:"); + + fprintf(output.stream, "%c", f_string_eol[0]); + + fprintf(output.stream, " This program will print the content associated with the given object and content data based on the FSS-0002 Basic List standard.%c", f_string_eol[0]); + + fprintf(output.stream, "%c", f_string_eol[0]); + + fprintf(output.stream, " When using the "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_depth); + fprintf(output.stream, " option, an order of operations is enforced on the parameters.%c", f_string_eol[0]); + + fprintf(output.stream, " When this order of operations is in effect, parameters to the right of a depth parameter are influenced by that depth parameter:%c", f_string_eol[0]); + + fprintf(output.stream, " "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_at); + fprintf(output.stream, ": An object index at the specified depth.%c", f_string_eol[0]); + + fprintf(output.stream, " "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_depth); + fprintf(output.stream, ": A new depth within the specified depth, indexed from the root.%c", f_string_eol[0]); + + fprintf(output.stream, " "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_name); + fprintf(output.stream, ": An object name at the specified depth.%c", f_string_eol[0]); + + fprintf(output.stream, "%c", f_string_eol[0]); + + fprintf(output.stream, " The parameter "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_depth); + fprintf(output.stream, " must be in numeric order, but values in between may be skipped.%c", f_string_eol[0]); + fprintf(output.stream, " ('-d 0 -a 1 -d 2 -a 2' would specify index 1 at depth 0, any index at depth 1, and index 2 at depth 2.)%c", f_string_eol[0]); + fprintf(output.stream, " ('-d 2 -a 1 -d 0 -a 2' would be invalid because depth 2 is before depth 1.)%c", f_string_eol[0]); + + fprintf(output.stream, "%c", f_string_eol[0]); + + fprintf(output.stream, " The parameter "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_select); + fprintf(output.stream, " selects a content index at a given depth.%c", f_string_eol[0]); + fprintf(output.stream, " (This parameter is not synonymous with the depth parameter and does not relate to nested content).%c", f_string_eol[0]); + + fprintf(output.stream, "%c", f_string_eol[0]); + + fprintf(output.stream, " Specify both "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_object); + fprintf(output.stream, " and the "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_total); + fprintf(output.stream, " parameters to get the total objects.%c", f_string_eol[0]); + + fprintf(output.stream, "%c", f_string_eol[0]); + + fprintf(output.stream, " When both "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_at); + fprintf(output.stream, " and "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_name); + fprintf(output.stream, " parameters are specified (at the same depth), the "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_at); + fprintf(output.stream, " parameter value will be treated as a position relative to the specified "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_name); + fprintf(output.stream, " parameter value.%c", f_string_eol[0]); + + fprintf(output.stream, "%c", f_string_eol[0]); + + fprintf(output.stream, " This program may support parameters, such as "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_depth); + fprintf(output.stream, " or "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_select); + fprintf(output.stream, ", even if not supported by the standard.%c", f_string_eol[0]); + fprintf(output.stream, " This is done to help ensure consistency for scripting.%c", f_string_eol[0]); + + fprintf(output.stream, "%c", f_string_eol[0]); + + fprintf(output.stream, " For parameters like "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_depth); + fprintf(output.stream, ", if the standard doesn't support nested content, then only a depth of 0 would be valid.%c", f_string_eol[0]); + + fprintf(output.stream, " For parameters like "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_select); + fprintf(output.stream, ", if the standard doesn't support multiple content groups, then only a select of 0 would be valid.%c", f_string_eol[0]); + + fprintf(output.stream, "%c", f_string_eol[0]); + + fprintf(output.stream, " The parameter "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_trim); + fprintf(output.stream, " will remove leading and trailing whitespaces when selecting objects or when printing objects.%c", f_string_eol[0]); + + fprintf(output.stream, "%c", f_string_eol[0]); + + fprintf(output.stream, " When specifying both the "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_object); + fprintf(output.stream, " parameter and the "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_content); + fprintf(output.stream, " parameter, the entire object and content are printed, including the formatting.%c", f_string_eol[0]); + fprintf(output.stream, " Both the object and content printed are already escaped.%c", f_string_eol[0]); + fprintf(output.stream, " Both the object and content are separated by an EOL.%c", f_string_eol[0]); + + fprintf(output.stream, "%c", f_string_eol[0]); + + fprintf(output.stream, " The parameter "); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_delimit); + fprintf(output.stream, " accepts the following:%c", f_string_eol[0]); + fprintf(output.stream, " - "); + fl_color_print(output.stream, context.set.notable, "%s", fss_embedded_list_read_delimit_mode_name_none); + fprintf(output.stream, ": Do not apply delimits.%c", f_string_eol[0]); + fprintf(output.stream, " - "); + fl_color_print(output.stream, context.set.notable, "%s", fss_embedded_list_read_delimit_mode_name_all); + fprintf(output.stream, ": (default) apply all delimits.%c", f_string_eol[0]); + fprintf(output.stream, " - a number, 0 or greater: apply delimits for the specified depth.%c", f_string_eol[0]); + fprintf(output.stream, " - a number, 0 or greater, followed by a "); + fl_color_print(output.stream, context.set.notable, "%s", fss_embedded_list_read_delimit_mode_name_greater); + fprintf(output.stream, ": (such as '1+') apply delimits for the specified depth and any greater depth (numerically).%c", f_string_eol[0]); + fprintf(output.stream, " - a number, 0 or greater, followed by a "); + fl_color_print(output.stream, context.set.notable, "%s", fss_embedded_list_read_delimit_mode_name_lesser); + fprintf(output.stream, ": (such as '1-') apply delimits for the specified depth and any lesser depth (numerically).%c", f_string_eol[0]); + + fprintf(output.stream, "%c", f_string_eol[0]); + + return F_none; + } +#endif // _di_fss_embedded_list_read_print_help_ + +#ifndef _di_fss_embedded_list_read_main_ + f_return_status fss_embedded_list_read_main(const f_console_arguments_t arguments, fss_embedded_list_read_data_t *data) { + f_status_t status = F_none; + + { + const f_console_parameters_t parameters = f_macro_console_parameters_t_initialize(data->parameters, fss_embedded_list_read_total_parameters); + + { + f_console_parameter_id_t ids[3] = { fss_embedded_list_read_parameter_no_color, fss_embedded_list_read_parameter_light, fss_embedded_list_read_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_embedded_list_read_delete_data(data); + return F_status_set_error(status); + } + } + + // Identify priority of verbosity related parameters. + { + f_console_parameter_id_t ids[4] = { fss_embedded_list_read_parameter_verbosity_quiet, fss_embedded_list_read_parameter_verbosity_normal, fss_embedded_list_read_parameter_verbosity_verbose, fss_embedded_list_read_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_embedded_list_read_delete_data(data); + return status; + } + + if (choice == fss_embedded_list_read_parameter_verbosity_quiet) { + data->error.verbosity = f_console_verbosity_quiet; + } + else if (choice == fss_embedded_list_read_parameter_verbosity_normal) { + data->error.verbosity = f_console_verbosity_normal; + } + else if (choice == fss_embedded_list_read_parameter_verbosity_verbose) { + data->error.verbosity = f_console_verbosity_verbose; + } + else if (choice == fss_embedded_list_read_parameter_verbosity_debug) { + data->error.verbosity = f_console_verbosity_debug; + } + } + + status = F_none; + } + + if (data->parameters[fss_embedded_list_read_parameter_help].result == f_console_result_found) { + fss_embedded_list_read_print_help(data->output, data->context); + + fss_embedded_list_read_delete_data(data); + return F_none; + } + + if (data->parameters[fss_embedded_list_read_parameter_version].result == f_console_result_found) { + fll_program_print_version(data->output, fss_embedded_list_read_version); + + fss_embedded_list_read_delete_data(data); + return F_none; + } + + if (data->remaining.used > 0 || data->process_pipe) { + if (data->parameters[fss_embedded_list_read_parameter_at].result == f_console_result_found) { + 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_embedded_list_read_long_at); + fl_color_print(data->error.to.stream, data->context.set.error, "' requires a positive number.%c", f_string_eol[0]); + + status = F_status_set_error(F_parameter); + } + + if (F_status_is_error_not(status) && data->parameters[fss_embedded_list_read_parameter_depth].result == f_console_result_found) { + 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_embedded_list_read_long_depth); + fl_color_print(data->error.to.stream, data->context.set.error, "' requires a positive number.%c", f_string_eol[0]); + + status = F_status_set_error(F_parameter); + } + + if (F_status_is_error_not(status) && data->parameters[fss_embedded_list_read_parameter_line].result == f_console_result_found) { + 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_embedded_list_read_long_line); + fl_color_print(data->error.to.stream, data->context.set.error, "' requires a positive number.%c", f_string_eol[0]); + + status = F_status_set_error(F_parameter); + } + + if (F_status_is_error_not(status) && data->parameters[fss_embedded_list_read_parameter_name].result == f_console_result_found) { + 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_embedded_list_read_long_name); + fl_color_print(data->error.to.stream, data->context.set.error, "' requires a string.%c", f_string_eol[0]); + + status = F_status_set_error(F_parameter); + } + + if (F_status_is_error_not(status) && data->parameters[fss_embedded_list_read_parameter_select].result == f_console_result_found) { + 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_embedded_list_read_long_select); + fl_color_print(data->error.to.stream, data->context.set.error, "' requires a positive number.%c", f_string_eol[0]); + + status = F_status_set_error(F_parameter); + } + + if (data->parameters[fss_embedded_list_read_parameter_object].result == f_console_result_found) { + if (F_status_is_error_not(status) && data->parameters[fss_embedded_list_read_parameter_line].result == f_console_result_additional) { + fl_color_print(data->error.to.stream, data->context.set.error, "%sCannot specify the '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_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_embedded_list_read_long_line); + 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->parameters[fss_embedded_list_read_parameter_select].result == f_console_result_additional) { + fl_color_print(data->error.to.stream, data->context.set.error, "%sCannot specify the '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_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_embedded_list_read_long_select); + 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 (data->parameters[fss_embedded_list_read_parameter_content].result == f_console_result_found) { + if (F_status_is_error_not(status) && data->parameters[fss_embedded_list_read_parameter_total].result == f_console_result_found) { + fl_color_print(data->error.to.stream, data->context.set.error, "%sCannot 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_embedded_list_read_long_object); + fl_color_print(data->error.to.stream, data->context.set.error, "' and the '"); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_content); + 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_embedded_list_read_long_total); + 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 (data->parameters[fss_embedded_list_read_parameter_line].result == f_console_result_additional) { + if (F_status_is_error_not(status) && data->parameters[fss_embedded_list_read_parameter_total].result == f_console_result_found) { + fl_color_print(data->error.to.stream, data->context.set.error, "%sCannot specify the '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_line); + 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_embedded_list_read_long_total); + 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 (data->parameters[fss_embedded_list_read_parameter_pipe].result == f_console_result_found) { + if (F_status_is_error_not(status) && data->parameters[fss_embedded_list_read_parameter_total].result == f_console_result_found) { + fl_color_print(data->error.to.stream, data->context.set.error, "%sCannot specify the '", fll_error_print_error); + fl_color_print(data->error.to.stream, data->context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_pipe); + 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_embedded_list_read_long_total); + 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)) { + if (data->parameters[fss_embedded_list_read_parameter_delimit].result == f_console_result_found) { + 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_embedded_list_read_long_delimit); + fl_color_print(data->error.to.stream, data->context.set.error, "' requires a value.%c", f_string_eol[0]); + + status = F_status_set_error(F_parameter); + } + else if (data->parameters[fss_embedded_list_read_parameter_delimit].result == f_console_result_additional) { + const f_string_length_t location = data->parameters[fss_embedded_list_read_parameter_delimit].values.array[0]; + f_string_length_t length = strnlen(arguments.argv[location], f_console_length_size); + + if (length == 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_embedded_list_read_long_delimit); + fl_color_print(data->error.to.stream, data->context.set.error, "' must not be empty.%c", f_string_eol[0]); + + status = F_status_set_error(F_parameter); + } + else if (fl_string_compare(arguments.argv[location], fss_embedded_list_read_delimit_mode_name_none, length, fss_embedded_list_read_delimit_mode_name_none_length) == F_equal_to) { + data->delimit_mode = fss_embedded_list_read_delimit_mode_none; + } + else if (fl_string_compare(arguments.argv[location], fss_embedded_list_read_delimit_mode_name_all, length, fss_embedded_list_read_delimit_mode_name_all_length) == F_equal_to) { + data->delimit_mode = fss_embedded_list_read_delimit_mode_all; + } + else { + data->delimit_mode = fss_embedded_list_read_delimit_mode_depth; + + if (arguments.argv[location][length - 1] == fss_embedded_list_read_delimit_mode_name_greater[0]) { + data->delimit_mode = fss_embedded_list_read_delimit_mode_depth_greater; + + // shorten the length to better convert the remainder to a number. + length--; + } + else if (arguments.argv[location][length - 1] == fss_embedded_list_read_delimit_mode_name_lesser[0]) { + data->delimit_mode = fss_embedded_list_read_delimit_mode_depth_lesser; + + // shorten the length to better convert the remainder to a number. + length--; + } + + f_string_range_t range = f_macro_string_range_t_initialize(length); + + // ignore leading plus sign. + if (arguments.argv[location][0] == '+') { + range.start++; + } + + status = fl_conversion_string_to_number_unsigned(arguments.argv[location], &data->delimit_depth, range); + + if (F_status_is_error(status)) { + fll_error_parameter_integer_print(data->error, F_status_set_fine(status), "fl_conversion_string_to_number_unsigned", F_true, fss_embedded_list_read_long_delimit, arguments.argv[location]); + } + } + } + } + + fss_embedded_list_read_depths_t depths = fss_embedded_list_read_depths_t_initialize; + + f_fss_delimits_t objects_delimits = f_fss_delimits_t_initialize; + f_fss_delimits_t contents_delimits = f_fss_delimits_t_initialize; + f_fss_comments_t comments = f_fss_comments_t_initialize; + + f_string_length_t original_size = data->quantity.total; + + if (F_status_is_error_not(status)) { + status = fss_embedded_list_read_main_preprocess_depth(arguments, *data, &depths); + + if (F_status_is_error(status)) { + fll_error_print(data->error, F_status_set_fine(status), "fss_embedded_list_read_main_preprocess_depth", F_true); + } + } + + if (F_status_is_error_not(status) && data->parameters[fss_embedded_list_read_parameter_select].result == f_console_result_found) { + 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_embedded_list_read_long_select); + fl_color_print(data->error.to.stream, data->context.set.error, "' parameter requires a positive number.%c", f_string_eol[0]); + + status = F_status_set_error(F_parameter); + } + + if (F_status_is_error_not(status) && data->process_pipe) { + f_file_t file = f_file_t_initialize; + + file.id = f_type_descriptor_input; + + status = f_file_read(file, &data->buffer); + + if (F_status_is_error(status)) { + fll_error_file_print(data->error, F_status_set_fine(status), "f_file_read", F_true, "-", "read", fll_error_file_type_pipe); + } + else { + status = fss_embedded_list_read_main_process_file(arguments, data, "-", depths, &objects_delimits, &contents_delimits, &comments); + + if (F_status_is_error(status)) { + fll_error_file_print(data->error, F_status_set_fine(status), "fss_embedded_list_read_main_process_file", F_true, "-", "read", fll_error_file_type_pipe); + } + } + + // Clear buffers before continuing. + f_macro_fss_nest_t_delete_simple(data->nest); + f_macro_string_dynamic_t_delete_simple(data->buffer); + } + + if (F_status_is_error_not(status) && data->remaining.used > 0) { + for (f_array_length_t i = 0; i < data->remaining.used; i++) { + f_file_t file = f_file_t_initialize; + + status = f_file_open(arguments.argv[data->remaining.array[i]], 0, &file); + + data->quantity.total = original_size; + + if (F_status_is_error(status)) { + fll_error_file_print(data->error, F_status_set_fine(status), "f_file_open", F_true, arguments.argv[data->remaining.array[i]], "open", fll_error_file_type_file); + break; + } + + if (!data->quantity.total) { + status = f_file_size_by_id(file.id, &data->quantity.total); + if (F_status_is_error(status)) { + fll_error_file_print(data->error, F_status_set_fine(status), "f_file_size_by_id", F_true, arguments.argv[data->remaining.array[i]], "read", fll_error_file_type_file); + + f_file_stream_close(F_true, &file); + break; + } + + // Skip past empty files. + if (!data->quantity.total) { + if (data->parameters[fss_embedded_list_read_parameter_total].result == f_console_result_found) { + fprintf(data->output.stream, "0%c", f_string_eol[0]); + } + + f_file_stream_close(F_true, &file); + continue; + } + } + + status = f_file_read_until(file, data->quantity.total, &data->buffer); + + f_file_stream_close(F_true, &file); + + if (F_status_is_error(status)) { + fll_error_file_print(data->error, F_status_set_fine(status), "f_file_read_until", F_true, arguments.argv[data->remaining.array[i]], "read", fll_error_file_type_file); + break; + } + + status = fss_embedded_list_read_main_process_file(arguments, data, arguments.argv[data->remaining.array[i]], depths, &objects_delimits, &contents_delimits, &comments); + + if (F_status_is_error(status)) { + fll_error_file_print(data->error, F_status_set_fine(status), "fss_embedded_list_read_main_process_file", F_true, arguments.argv[data->remaining.array[i]], "read", fll_error_file_type_file); + break; + } + + // Clear buffers before repeating the loop. + f_macro_fss_nest_t_delete_simple(data->nest); + f_macro_string_dynamic_t_delete_simple(data->buffer); + } // for + + if (F_status_is_error(status)) { + f_macro_fss_nest_t_delete_simple(data->nest); + f_macro_string_dynamic_t_delete_simple(data->buffer); + } + } + + macro_fss_embedded_list_read_depths_t_delete_simple(depths); + f_macro_fss_delimits_t_delete_simple(objects_delimits); + f_macro_fss_delimits_t_delete_simple(contents_delimits); + f_macro_fss_comments_t_delete_simple(comments); + } + else { + fl_color_print(data->error.to.stream, data->context.set.error, "%sYou failed to specify one or more files.%c", fll_error_print_error, f_string_eol[0]); + status = F_status_set_error(F_parameter); + } + + fss_embedded_list_read_delete_data(data); + return status; + } +#endif // _di_fss_embedded_list_read_main_ + +#ifndef _di_fss_embedded_list_read_delete_data_ + f_return_status fss_embedded_list_read_delete_data(fss_embedded_list_read_data_t *data) { + + for (f_string_length_t i = 0; i < fss_embedded_list_read_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].values); + } // for + + f_macro_fss_nest_t_delete_simple(data->nest); + + f_macro_string_dynamic_t_delete_simple(data->buffer); + f_macro_string_lengths_t_delete_simple(data->remaining); + + f_macro_color_context_t_delete_simple(data->context); + + return F_none; + } +#endif // _di_fss_embedded_list_read_delete_data_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_3/fss_embedded_list_read/c/fss_embedded_list_read.h b/level_3/fss_embedded_list_read/c/fss_embedded_list_read.h new file mode 100644 index 0000000..255c83d --- /dev/null +++ b/level_3/fss_embedded_list_read/c/fss_embedded_list_read.h @@ -0,0 +1,263 @@ +/** + * FLL - Level 3 + * + * Project: FSS + * API Version: 0.5 + * Licenses: lgplv2.1 + * + * This is the FSS Basic List Read program + * This program utilizes the Featureless Linux Library. + * This program processes files or other input in fss format and stores the results in the fss_embedded_list_read_data_t. + * + * This processes in accordance to the FSS-0008 Embedded List specification. + */ +#ifndef _fss_embedded_list_read_h + +// libc includes +#include +#include +#include +#include + +// fll-0 includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// fll-1 includes +#include +#include +#include +#include +#include + +// fll-2 includes +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fss_embedded_list_read_version_ + #define fss_embedded_list_read_major_version "0" + #define fss_embedded_list_read_minor_version "5" + #define fss_embedded_list_read_micro_version "2" + #define fss_embedded_list_read_version fss_embedded_list_read_major_version "." fss_embedded_list_read_minor_version "." fss_embedded_list_read_micro_version +#endif // _di_fss_embedded_list_read_version_ + +#ifndef _di_fss_embedded_list_read_name_ + #define fss_embedded_list_read_name "fss_embedded_list_read" + #define fss_embedded_list_read_name_long "FSS Embedded List Read" +#endif // _di_fss_embedded_list_read_name_ + +#ifndef _di_fss_embedded_list_read_defines_ + #define fss_embedded_list_read_pipe_content_end '\f' + #define fss_embedded_list_read_pipe_content_ignore '\v' + #define fss_embedded_list_read_pipe_content_start '\b' + + #define fss_embedded_list_read_short_at "a" + #define fss_embedded_list_read_short_content "c" + #define fss_embedded_list_read_short_delimit "D" + #define fss_embedded_list_read_short_depth "d" + #define fss_embedded_list_read_short_empty "e" + #define fss_embedded_list_read_short_line "l" + #define fss_embedded_list_read_short_name "n" + #define fss_embedded_list_read_short_object "o" + #define fss_embedded_list_read_short_pipe "p" + #define fss_embedded_list_read_short_select "s" + #define fss_embedded_list_read_short_total "t" + #define fss_embedded_list_read_short_trim "T" + + #define fss_embedded_list_read_long_at "at" + #define fss_embedded_list_read_long_content "content" + #define fss_embedded_list_read_long_delimit "delimit" + #define fss_embedded_list_read_long_depth "depth" + #define fss_embedded_list_read_long_empty "empty" + #define fss_embedded_list_read_long_line "line" + #define fss_embedded_list_read_long_name "name" + #define fss_embedded_list_read_long_object "object" + #define fss_embedded_list_read_long_pipe "pipe" + #define fss_embedded_list_read_long_select "select" + #define fss_embedded_list_read_long_total "total" + #define fss_embedded_list_read_long_trim "trim" + + enum { + fss_embedded_list_read_parameter_help, + fss_embedded_list_read_parameter_light, + fss_embedded_list_read_parameter_dark, + fss_embedded_list_read_parameter_no_color, + fss_embedded_list_read_parameter_verbosity_quiet, + fss_embedded_list_read_parameter_verbosity_normal, + fss_embedded_list_read_parameter_verbosity_verbose, + fss_embedded_list_read_parameter_verbosity_debug, + fss_embedded_list_read_parameter_version, + + fss_embedded_list_read_parameter_at, + fss_embedded_list_read_parameter_content, + fss_embedded_list_read_parameter_delimit, + fss_embedded_list_read_parameter_depth, + fss_embedded_list_read_parameter_empty, + fss_embedded_list_read_parameter_line, + fss_embedded_list_read_parameter_name, + fss_embedded_list_read_parameter_object, + fss_embedded_list_read_parameter_pipe, + fss_embedded_list_read_parameter_select, + fss_embedded_list_read_parameter_total, + fss_embedded_list_read_parameter_trim, + }; + + #define fss_embedded_list_read_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, 0, 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_embedded_list_read_short_at, fss_embedded_list_read_long_at, 0, 1, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_embedded_list_read_short_content, fss_embedded_list_read_long_content, 0, 0, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_embedded_list_read_short_delimit, fss_embedded_list_read_long_delimit, 0, 1, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_embedded_list_read_short_depth, fss_embedded_list_read_long_depth, 0, 1, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_embedded_list_read_short_empty, fss_embedded_list_read_long_empty, 0, 0, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_embedded_list_read_short_line, fss_embedded_list_read_long_line, 0, 1, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_embedded_list_read_short_name, fss_embedded_list_read_long_name, 0, 1, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_embedded_list_read_short_object, fss_embedded_list_read_long_object, 0, 0, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_embedded_list_read_short_pipe, fss_embedded_list_read_long_pipe, 0, 0, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_embedded_list_read_short_select, fss_embedded_list_read_long_select, 0, 1, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_embedded_list_read_short_total, fss_embedded_list_read_long_total, 0, 0, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_embedded_list_read_short_trim, fss_embedded_list_read_long_trim, 0, 0, f_console_type_normal), \ + } + + #define fss_embedded_list_read_total_parameters 21 +#endif // _di_fss_embedded_list_read_defines_ + +#ifndef _di_fss_embedded_list_read_delimit_mode_ + #define fss_embedded_list_read_delimit_mode_name_none "none" + #define fss_embedded_list_read_delimit_mode_name_all "all" + #define fss_embedded_list_read_delimit_mode_name_greater "+" + #define fss_embedded_list_read_delimit_mode_name_lesser "-" + + #define fss_embedded_list_read_delimit_mode_name_none_length 4 + #define fss_embedded_list_read_delimit_mode_name_all_length 3 + #define fss_embedded_list_read_delimit_mode_name_greater_length 1 + #define fss_embedded_list_read_delimit_mode_name_lesser_length 1 + + enum { + fss_embedded_list_read_delimit_mode_none = 1, + fss_embedded_list_read_delimit_mode_all, + fss_embedded_list_read_delimit_mode_depth, + fss_embedded_list_read_delimit_mode_depth_greater, + fss_embedded_list_read_delimit_mode_depth_lesser, + }; +#endif // _di_fss_embedded_list_read_delimit_modes_ + +#ifndef _di_fss_embedded_list_read_data_t_ + typedef struct { + f_console_parameter_t parameters[fss_embedded_list_read_total_parameters]; + + f_string_lengths_t remaining; + bool process_pipe; + + f_file_t output; + fll_error_print_t error; + + f_string_dynamic_t buffer; + f_fss_nest_t nest; + f_string_quantity_t quantity; + + uint8_t delimit_mode; + f_string_length_t delimit_depth; + + f_color_context_t context; + } fss_embedded_list_read_data_t; + + #define fss_embedded_list_read_data_t_initialize \ + { \ + fss_embedded_list_read_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_dynamic_t_initialize, \ + f_fss_nest_t_initialize, \ + f_string_quantity_t_initialize, \ + fss_embedded_list_read_delimit_mode_all, \ + 0, \ + f_color_context_t_initialize, \ + } +#endif // _di_fss_embedded_list_read_data_t_ + +/** + * Print help. + * + * @param output + * The file to print to. + * @param context + * The color context settings. + * + * @return + * F_none on success. + */ +#ifndef _di_fss_embedded_list_read_print_help_ + extern f_return_status fss_embedded_list_read_print_help(const f_file_t output, const f_color_context_t context); +#endif // _di_fss_embedded_list_read_print_help_ + +/** + * Execute main program. + * + * Be sure to call fss_embedded_list_read_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_embedded_list_read_delete_data() + */ +#ifndef _di_fss_embedded_list_read_main_ + extern f_return_status fss_embedded_list_read_main(const f_console_arguments_t arguments, fss_embedded_list_read_data_t *data); +#endif // _di_fss_embedded_list_read_main_ + +/** + * Deallocate data. + * + * Be sure to call this after executing fss_embedded_list_read_main(). + * + * @param data + * The program data. + * + * @return + * F_none on success. + * + * Status codes (with error bit) are returned on any problem. + * + * @see fss_embedded_list_read_main() + */ +#ifndef _di_fss_embedded_list_read_delete_data_ + extern f_return_status fss_embedded_list_read_delete_data(fss_embedded_list_read_data_t *data); +#endif // _di_fss_embedded_list_read_delete_data_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _fss_embedded_list_read_h diff --git a/level_3/fss_embedded_list_read/c/main.c b/level_3/fss_embedded_list_read/c/main.c new file mode 100644 index 0000000..904d21f --- /dev/null +++ b/level_3/fss_embedded_list_read/c/main.c @@ -0,0 +1,16 @@ +#include "fss_embedded_list_read.h" + +int main(const unsigned long argc, const f_string_t *argv) { + const f_console_arguments_t arguments = { argc, argv }; + fss_embedded_list_read_data_t data = fss_embedded_list_read_data_t_initialize; + + if (f_pipe_input_exists()) { + data.process_pipe = F_true; + } + + if (F_status_is_error(fss_embedded_list_read_main(arguments, &data))) { + return 1; + } + + return 0; +} diff --git a/level_3/fss_embedded_list_read/c/private-fss_embedded_list_read.c b/level_3/fss_embedded_list_read/c/private-fss_embedded_list_read.c new file mode 100644 index 0000000..d9539ca --- /dev/null +++ b/level_3/fss_embedded_list_read/c/private-fss_embedded_list_read.c @@ -0,0 +1,894 @@ +#include "fss_embedded_list_read.h" +#include "private-fss_embedded_list_read.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fss_embedded_list_read_main_preprocess_depth_ + f_return_status fss_embedded_list_read_main_preprocess_depth(const f_console_arguments_t arguments, const fss_embedded_list_read_data_t data, fss_embedded_list_read_depths_t *depths) { + f_status_t status = F_none; + + const f_array_length_t values_total = data.parameters[fss_embedded_list_read_parameter_depth].values.used + data.parameters[fss_embedded_list_read_parameter_at].values.used + data.parameters[fss_embedded_list_read_parameter_name].values.used; + + f_array_length_t values_order[values_total]; + f_array_length_t values_type[values_total]; + + f_array_length_t i = 0; + f_array_length_t j = 0; + + // determine the linear order in which all of the three parameter values are to be applied. + if (values_total) { + memset(values_order, 0, values_total); + + f_array_length_t k = 0; + f_array_length_t l = 0; + + for (; j < data.parameters[fss_embedded_list_read_parameter_depth].values.used; ++j) { + + values_order[i] = data.parameters[fss_embedded_list_read_parameter_depth].values.array[j]; + values_type[i++] = fss_embedded_list_read_parameter_depth; + } // for + + if (i) { + for (j = 0; j < data.parameters[fss_embedded_list_read_parameter_at].values.used; ++j) { + + for (k = 0; k < i; ++k) { + + if (values_order[k] > data.parameters[fss_embedded_list_read_parameter_at].values.array[j]) { + for (l = i; l > k; --l) { + values_order[l] = values_order[l - 1]; + values_type[l] = values_type[l - 1]; + } // for + + values_order[k] = data.parameters[fss_embedded_list_read_parameter_at].values.array[j]; + values_type[k] = fss_embedded_list_read_parameter_at; + i++; + break; + } + } // for + + if (k == i) { + values_order[i] = data.parameters[fss_embedded_list_read_parameter_at].values.array[j]; + values_type[i++] = fss_embedded_list_read_parameter_at; + } + } // for + } + else { + for (; j < data.parameters[fss_embedded_list_read_parameter_at].values.used; ++j) { + + values_order[i] = data.parameters[fss_embedded_list_read_parameter_at].values.array[j]; + values_type[i++] = fss_embedded_list_read_parameter_at; + } // for + } + + if (i) { + for (j = 0; j < data.parameters[fss_embedded_list_read_parameter_name].values.used; ++j) { + + for (k = 0; k < i; ++k) { + + if (values_order[k] > data.parameters[fss_embedded_list_read_parameter_name].values.array[j]) { + for (l = i; l > k; --l) { + values_order[l] = values_order[l - 1]; + values_type[l] = values_type[l - 1]; + } // for + + values_order[k] = data.parameters[fss_embedded_list_read_parameter_name].values.array[j]; + values_type[k] = fss_embedded_list_read_parameter_name; + i++; + break; + } + } // for + + if (k == i) { + values_order[i] = data.parameters[fss_embedded_list_read_parameter_name].values.array[j]; + values_type[i++] = fss_embedded_list_read_parameter_name; + } + } // for + } + else { + for (; j < data.parameters[fss_embedded_list_read_parameter_name].values.used; ++j) { + + values_order[i] = data.parameters[fss_embedded_list_read_parameter_name].values.array[j]; + values_type[i++] = fss_embedded_list_read_parameter_name; + } // for + } + } + + { + i = 1; + + if (data.parameters[fss_embedded_list_read_parameter_depth].result == f_console_result_additional) { + i = data.parameters[fss_embedded_list_read_parameter_depth].values.used + 1; + } + + macro_fss_embedded_list_read_depths_t_new(status, (*depths), i); + + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "fss_embedded_list_read_main_preprocess_depth", F_true); + return status; + } + } + + // provide default level-0 depth values. + depths->array[0].depth = 0; + depths->array[0].index_at = 0; + depths->array[0].index_name = 0; + depths->array[0].value_at = 0; + + { + f_number_unsigned_t number = 0; + bool first_depth = F_true; + + for (i = 0; i < values_total; ++i) { + + if (values_type[i] == fss_embedded_list_read_parameter_depth || values_type[i] == fss_embedded_list_read_parameter_at) { + const f_string_range_t range = f_macro_string_range_t_initialize(strlen(arguments.argv[values_order[i]])); + + status = fl_conversion_string_to_number_unsigned(arguments.argv[values_order[i]], &number, range); + + if (F_status_is_error(status)) { + fll_error_parameter_integer_print(data.error, F_status_set_fine(status), "fl_conversion_string_to_number_unsigned", F_true, fss_embedded_list_read_long_depth, arguments.argv[values_order[i]]); + return status; + } + } + + if (values_type[i] == fss_embedded_list_read_parameter_depth) { + + if (first_depth) { + if (i && number) { + depths->array[++depths->used].index_at = 0; + depths->array[depths->used].index_name = 0; + depths->array[depths->used].value_at = 0; + } + + first_depth = F_false; + depths->array[depths->used].depth = number; + } + else { + depths->array[++depths->used].depth = number; + depths->array[depths->used].index_at = 0; + depths->array[depths->used].index_name = 0; + depths->array[depths->used].value_at = 0; + } + } + else if (values_type[i] == fss_embedded_list_read_parameter_at) { + depths->array[depths->used].index_at = values_order[i]; + depths->array[depths->used].value_at = number; + } + else if (values_type[i] == fss_embedded_list_read_parameter_name) { + depths->array[depths->used].index_name = values_order[i]; + depths->array[depths->used].value_name.used = 0; + + if (data.parameters[fss_embedded_list_read_parameter_trim].result == f_console_result_found) { + status = fl_string_rip(arguments.argv[values_order[i]], strnlen(arguments.argv[values_order[i]], f_console_length_size), &depths->array[depths->used].value_name); + + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "fl_string_rip", F_true); + return status; + } + } + else { + status = fl_string_append(arguments.argv[values_order[i]], strnlen(arguments.argv[values_order[i]], f_console_length_size), &depths->array[depths->used].value_name); + + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "fl_string_append", F_true); + return status; + } + } + } + } // for + + depths->used++; + } + + for (i = 0; i < depths->used; i++) { + + for (j = i + 1; j < depths->used; j++) { + + if (depths->array[i].depth == depths->array[j].depth) { + fprintf(data.error.to.stream, "%c", f_string_eol[0]); + fl_color_print(data.error.to.stream, data.context.set.error, "%sThe value '", fll_error_print_error); + fl_color_print(data.error.to.stream, data.context.set.notable, "%llu", depths->array[i].depth); + fl_color_print(data.error.to.stream, data.context.set.error, "' may only be specified once for the parameter '"); + fl_color_print(data.error.to.stream, data.context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_read_long_depth); + fl_color_print(data.error.to.stream, data.context.set.error, "'.%c", f_string_eol[0]); + + return F_status_set_error(F_parameter); + } + else if (depths->array[i].depth > depths->array[j].depth) { + 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_embedded_list_read_long_depth); + fl_color_print(data.error.to.stream, data.context.set.error, "' may not have the value '"); + fl_color_print(data.error.to.stream, data.context.set.notable, "%llu", depths->array[i].depth); + fl_color_print(data.error.to.stream, data.context.set.error, "' before the value '"); + fl_color_print(data.error.to.stream, data.context.set.notable, "%llu", depths->array[j].depth); + fl_color_print(data.error.to.stream, data.context.set.error, "'.%c", f_string_eol[0]); + + return F_status_set_error(F_parameter); + } + } // for + } // for + + return F_none; + } +#endif // _di_fss_embedded_list_read_main_preprocess_depth_ + +#ifndef _di_fss_embedded_list_read_main_process_file_ + f_return_status fss_embedded_list_read_main_process_file(const f_console_arguments_t arguments, fss_embedded_list_read_data_t *data, const f_string_t filename, const fss_embedded_list_read_depths_t depths, f_fss_delimits_t *objects_delimits, f_fss_delimits_t *contents_delimits, f_fss_comments_t *comments) { + f_status_t status = F_none; + + { + f_string_range_t input = f_macro_string_range_t_initialize(data->buffer.used); + + objects_delimits->used = 0; + contents_delimits->used = 0; + comments->used = 0; + + status = fll_fss_embedded_list_read(&data->buffer, &input, &data->nest, objects_delimits, contents_delimits, comments); + + if (F_status_is_error(status)) { + // @todo: detect and replace fll_error_file_type_file with fll_error_file_type_pipe as appropriate. + fll_error_file_print(data->error, F_status_set_fine(status), "fll_fss_embedded_list_read", F_true, filename, "process", fll_error_file_type_file); + } + else if (status == F_data_not_stop || status == F_data_not_eos) { + f_macro_fss_nest_t_delete_simple(data->nest); + f_macro_string_dynamic_t_delete_simple(data->buffer); + + if (data->parameters[fss_embedded_list_read_parameter_total].result == f_console_result_found) { + fprintf(data->output.stream, "0%c", f_string_eol[0]); + return F_none; + } + + return F_status_set_warning(status); + } + + if (F_status_is_error(status)) { + f_macro_fss_nest_t_delete_simple(data->nest); + f_macro_string_dynamic_t_delete_simple(data->buffer); + + return status; + } + + f_array_length_t i = 0; + f_array_length_t j = 0; + + // comments are not to be part of the file, so remove them. + for (; i < comments->used; ++i) { + for (j = comments->array[i].start; j <= comments->array[i].stop; ++j) { + data->buffer.string[j] = f_fss_delimit_placeholder; + } // for + } // for + } + + // Requested depths cannot be greater than contents depth. + if (depths.used > data->nest.used) { + if (data->parameters[fss_embedded_list_read_parameter_total].result == f_console_result_found) { + fprintf(data->output.stream, "0%c", f_string_eol[0]); + return F_none; + } + + return F_none; + } + + { + f_number_unsigned_t select = 0; + + if (data->parameters[fss_embedded_list_read_parameter_select].result == f_console_result_additional) { + const f_string_length_t index = data->parameters[fss_embedded_list_read_parameter_select].values.array[data->parameters[fss_embedded_list_read_parameter_select].values.used - 1]; + const f_string_range_t range = f_macro_string_range_t_initialize(strlen(arguments.argv[index])); + + status = fl_conversion_string_to_number_unsigned(arguments.argv[index], &select, range); + + if (F_status_is_error(status)) { + fll_error_parameter_integer_print(data->error, F_status_set_fine(status), "fl_conversion_string_to_number_unsigned", F_true, fss_embedded_list_read_long_select, arguments.argv[index]); + return status; + } + + // This standard does not support multiple content groups. + if (select > 0) { + return F_none; + } + } + } + + f_array_length_t line = 0; + + if (data->parameters[fss_embedded_list_read_parameter_line].result == f_console_result_additional) { + const f_array_length_t index = data->parameters[fss_embedded_list_read_parameter_line].values.array[data->parameters[fss_embedded_list_read_parameter_line].values.used - 1]; + const f_string_range_t range = f_macro_string_range_t_initialize(strlen(arguments.argv[index])); + + status = fl_conversion_string_to_number_unsigned(arguments.argv[index], &line, range); + + if (F_status_is_error(status)) { + fll_error_parameter_integer_print(data->error, F_status_set_fine(status), "fl_conversion_string_to_number_unsigned", F_true, fss_embedded_list_read_long_line, arguments.argv[index]); + return status; + } + } + + fss_embedded_list_read_process_delimits(*data, objects_delimits, contents_delimits); + + const fss_embedded_list_read_skip_t parents = fss_embedded_list_read_skip_t_initialize; + + return fss_embedded_list_read_main_process_for_depth(arguments, filename, depths, 0, line, parents, data, objects_delimits, contents_delimits); + } +#endif // _di_fss_embedded_list_read_main_process_file_ + +#ifndef _di_fss_embedded_list_read_main_process_for_depth_ + f_return_status fss_embedded_list_read_main_process_for_depth(const f_console_arguments_t arguments, const f_string_t filename, const fss_embedded_list_read_depths_t depths, const f_array_length_t depths_index, const f_array_length_t line, const fss_embedded_list_read_skip_t parents, fss_embedded_list_read_data_t *data, f_fss_delimits_t *objects_delimits, f_fss_delimits_t *contents_delimits) { + + f_fss_items_t *items = &data->nest.depth[depths.array[depths_index].depth]; + + bool skip[items->used]; + + // setup defaults to be not skipped unless any given parent is skipped. + memset(skip, F_false, sizeof(skip) * items->used); + + if (parents.used) { + for (f_array_length_t i = 0; i < items->used; ++i) { + + if (items->array[i].parent >= parents.used || parents.skip[items->array[i].parent]) { + skip[i] = F_true; + } + } // for + } + + if (depths.array[depths_index].index_name || depths.array[depths_index].index_at) { + const f_string_lengths_t except_none = f_string_lengths_t_initialize; + + f_array_length_t i = 0; + f_array_length_t j = 0; + + if (!depths.array[depths_index].index_name || (depths.array[depths_index].index_at && depths.array[depths_index].index_at < depths.array[depths_index].index_name)) { + + // all other non-"at" parameters must be FALSE. + for (; i < items->used; ++i) { + + if (skip[i]) continue; + + if (j != depths.array[depths_index].value_at) { + skip[i] = F_true; + } + + ++j; + } // for + + if (depths.array[depths_index].value_at < items->used && !skip[depths.array[depths_index].value_at]) { + if (depths.array[depths_index].index_name) { + + if (data->parameters[fss_embedded_list_read_parameter_trim].result == f_console_result_found) { + + if (fl_string_dynamic_partial_compare_except_trim_dynamic(depths.array[depths_index].value_name, data->buffer, items->array[depths.array[depths_index].value_at].object, except_none, *objects_delimits) != F_equal_to) { + skip[depths.array[depths_index].value_at] = F_true; + } + } + else { + if (fl_string_dynamic_partial_compare_except_dynamic(depths.array[depths_index].value_name, data->buffer, items->array[depths.array[depths_index].value_at].object, except_none, *objects_delimits) != F_equal_to) { + skip[depths.array[depths_index].value_at] = F_true; + } + } + } + } + } + else { + + if (data->parameters[fss_embedded_list_read_parameter_trim].result == f_console_result_found) { + + for (i = 0; i < items->used; ++i) { + + if (skip[i]) continue; + + if (fl_string_dynamic_partial_compare_except_trim_dynamic(depths.array[depths_index].value_name, data->buffer, items->array[i].object, except_none, *objects_delimits) != F_equal_to) { + skip[i] = F_true; + } + } // for + } + else { + + for (i = 0; i < items->used; ++i) { + + if (skip[i]) continue; + + if (fl_string_dynamic_partial_compare_except_dynamic(depths.array[depths_index].value_name, data->buffer, items->array[i].object, except_none, *objects_delimits) != F_equal_to) { + skip[i] = F_true; + } + } // for + } + + if (depths.array[depths_index].index_at) { + + // all other non-"at" parameters must be FALSE. + for (i = 0, j = 0; i < items->used; ++i) { + + if (skip[i]) continue; + + if (j != depths.array[depths_index].value_at) { + skip[i] = F_true; + } + + ++j; + } // for + } + } + } + + // if the current depth is not the final depth, then recurse into the next depth. + if (depths_index + 1 < depths.used) { + bool skip_next[data->nest.depth[depths.array[depths_index + 1].depth - 1].used]; + + fss_embedded_list_read_skip_t parents_next = fss_embedded_list_read_skip_t_initialize; + + if (depths.array[depths_index].depth + 1 == depths.array[depths_index + 1].depth) { + parents_next.skip = skip; + parents_next.used = items->used; + } + else { + const f_array_length_t parents_depth = depths.array[depths_index + 1].depth - 1; + const f_array_length_t depth_next = depths.array[depths_index + 1].depth; + + parents_next.skip = skip_next; + parents_next.used = data->nest.depth[parents_depth].used; + + memset(skip_next, F_true, sizeof(skip_next) * parents_next.used); + + f_fss_items_t *items_next = &data->nest.depth[depth_next]; + f_fss_items_t *items_previous = 0; + f_fss_item_t *item_previous = 0; + + f_array_length_t i = 0; + f_array_length_t j = 0; + + for (; i < items_next->used; ++i) { + + j = depth_next; + + item_previous = &items_next->array[i]; + items_previous = &data->nest.depth[--j]; + + while (j > depths.array[depths_index].depth) { + + item_previous = &items_previous->array[item_previous->parent]; + items_previous = &data->nest.depth[--j]; + } // while + + if (skip[item_previous->parent]) { + skip_next[items_next->array[i].parent] = F_true; + } + else { + skip_next[items_next->array[i].parent] = F_false; + } + } // for + } + + return fss_embedded_list_read_main_process_for_depth(arguments, filename, depths, depths_index + 1, line, parents_next, data, objects_delimits, contents_delimits); + } + + // process objects. + f_array_length_t i = 0; + f_array_length_t j = 0; + + if (data->parameters[fss_embedded_list_read_parameter_object].result == f_console_result_found) { + if (data->parameters[fss_embedded_list_read_parameter_total].result == f_console_result_found) { + f_array_length_t total = 0; + + for (i = 0; i < items->used; i++) { + if (skip[i]) continue; + + total++; + } // for + + fprintf(data->output.stream, "%llu%c", total, f_string_eol[0]); + + return F_none; + } + + f_return_status (*print_object)(FILE *, const f_string_static_t, const f_string_range_t, const f_string_lengths_t) = &f_print_except_dynamic_partial; + + if (data->parameters[fss_embedded_list_read_parameter_trim].result == f_console_result_found) { + print_object = &fl_print_trim_except_dynamic_partial; + } + + for (i = 0; i < items->used; i++) { + + if (skip[i]) continue; + + print_object(data->output.stream, data->buffer, items->array[i].object, *objects_delimits); + + if (data->parameters[fss_embedded_list_read_parameter_content].result == f_console_result_found) { + fss_embedded_list_read_print_object_end(*data); + + if (items->array[i].content.used) { + f_print_except_dynamic_partial(data->output.stream, data->buffer, items->array[i].content.array[0], *contents_delimits); + } + } + + fss_embedded_list_read_print_set_end(*data); + } // for + + return F_none; + } + + // process contents. + bool include_empty = 0; + + if (data->parameters[fss_embedded_list_read_parameter_empty].result == f_console_result_found) { + include_empty = 1; + } + + if (data->parameters[fss_embedded_list_read_parameter_total].result == f_console_result_found) { + f_array_length_t total = 0; + + for (i = 0; i < items->used; ++i) { + + if (skip[i]) continue; + + if (!items->array[i].content.used) { + if (include_empty) { + total++; + } + + continue; + } + + for (j = items->array[i].content.array[0].start; j <= items->array[i].content.array[0].stop; ++j) { + + if (!data->buffer.string[j]) continue; + + if (data->buffer.string[j] == f_string_eol[0]) { + total++; + } + } // for + } // for + + fprintf(data->output.stream, "%llu%c", total, f_string_eol[0]); + return F_none; + } + + if (data->parameters[fss_embedded_list_read_parameter_line].result == f_console_result_additional) { + f_array_length_t line_current = 0; + + for (; i < items->used; ++i) { + + if (skip[i]) continue; + + if (!items->array[i].content.used) { + if (include_empty) { + if (line_current == line) { + fss_embedded_list_read_print_set_end(*data); + break; + } + + line_current++; + } + + continue; + } + + j = items->array[i].content.array[0].start; + + if (line_current != line) { + for (; j <= items->array[i].content.array[0].stop; ++j) { + + if (data->buffer.string[j] == f_string_eol[0]) { + line_current++; + + if (line_current == line) { + ++j; + break; + } + } + } // for + } + + if (line_current == line) { + if (j > items->array[i].content.array[0].stop) continue; + + for (; j <= items->array[i].content.array[0].stop; ++j) { + + if (!data->buffer.string[j]) continue; + + if (data->buffer.string[j] == f_string_eol[0]) { + fprintf(data->output.stream, "%c", f_string_eol[0]); + break; + } + + fprintf(data->output.stream, "%c", data->buffer.string[j]); + } // for + + break; + } + } // for + + return F_none; + } + + for (i = 0; i < items->used; i++) { + + if (skip[i]) continue; + + if (!items->array[i].content.used) { + if (include_empty) { + fss_embedded_list_read_print_set_end(*data); + } + + continue; + } + + f_print_except_dynamic_partial(data->output.stream, data->buffer, items->array[i].content.array[0], *contents_delimits); + + if (data->parameters[fss_embedded_list_read_parameter_pipe].result == f_console_result_found) { + fprintf(data->output.stream, "%c", fss_embedded_list_read_pipe_content_end); + } + } // for + + return F_none; + } +#endif // _di_fss_embedded_list_read_main_process_for_depth_ + +#ifndef _di_fss_embedded_list_read_print_object_end_ + void fss_embedded_list_read_print_object_end(const fss_embedded_list_read_data_t data) { + + if (data.parameters[fss_embedded_list_read_parameter_pipe].result == f_console_result_found) { + fprintf(data.output.stream, "%c", fss_embedded_list_read_pipe_content_start); + } + else { + if (data.parameters[fss_embedded_list_read_parameter_object].result == f_console_result_found && data.parameters[fss_embedded_list_read_parameter_content].result == f_console_result_found) { + fprintf(data.output.stream, "%c%c", f_fss_embedded_list_open, f_fss_embedded_list_open_end); + } + else { + fprintf(data.output.stream, "%c", f_fss_eol); + } + } + } +#endif // _di_fss_embedded_list_read_print_object_end_ + +#ifndef _di_fss_embedded_list_read_print_content_end_ + void fss_embedded_list_read_print_content_end(const fss_embedded_list_read_data_t data) { + + if (data.parameters[fss_embedded_list_read_parameter_pipe].result == f_console_result_found) { + fprintf(data.output.stream, "%c", fss_embedded_list_read_pipe_content_start); + } + else { + if (data.parameters[fss_embedded_list_read_parameter_object].result == f_console_result_found && data.parameters[fss_embedded_list_read_parameter_content].result == f_console_result_found) { + fprintf(data.output.stream, "%c%c", f_fss_embedded_list_close, f_fss_embedded_list_close_end); + } + else { + fprintf(data.output.stream, "%c", f_fss_eol); + } + } + } +#endif // _di_fss_embedded_list_read_print_content_end_ + +#ifndef _di_fss_embedded_list_read_print_content_ignore_ + void fss_embedded_list_read_print_content_ignore(const fss_embedded_list_read_data_t data) { + + if (data.parameters[fss_embedded_list_read_parameter_pipe].result == f_console_result_found) { + fprintf(data.output.stream, "%c", fss_embedded_list_read_pipe_content_ignore); + } + } +#endif // _di_fss_embedded_list_read_print_content_ignore_ + +#ifndef _di_fss_embedded_list_read_print_set_end_ + void fss_embedded_list_read_print_set_end(const fss_embedded_list_read_data_t data) { + + if (data.parameters[fss_embedded_list_read_parameter_pipe].result == f_console_result_found) { + fprintf(data.output.stream, "%c", fss_embedded_list_read_pipe_content_end); + } + else { + if (data.parameters[fss_embedded_list_read_parameter_object].result == f_console_result_found && data.parameters[fss_embedded_list_read_parameter_content].result == f_console_result_found) { + fprintf(data.output.stream, "%c%c", f_fss_embedded_list_close, f_fss_embedded_list_close_end); + } + else { + fprintf(data.output.stream, "%c", f_fss_eol); + } + } + } +#endif // _di_fss_embedded_list_read_print_set_end_ + +#ifndef _di_fss_embedded_list_read_process_delimits_ + void fss_embedded_list_read_process_delimits(const fss_embedded_list_read_data_t data, f_fss_delimits_t *objects_delimits, f_fss_delimits_t *contents_delimits) { + + if (!data.nest.used) return; + + if ((!objects_delimits->used && !contents_delimits->used) || data.delimit_mode == fss_embedded_list_read_delimit_mode_all) return; + + if (data.delimit_mode == fss_embedded_list_read_delimit_mode_depth_lesser && data.nest.used < data.delimit_depth) return; + if (data.delimit_mode == fss_embedded_list_read_delimit_mode_depth_greater && data.delimit_depth == 0) return; + + if (data.delimit_mode == fss_embedded_list_read_delimit_mode_none) { + objects_delimits->used = 0; + contents_delimits->used = 0; + return; + } + + if (data.delimit_mode == fss_embedded_list_read_delimit_mode_depth || data.delimit_mode == fss_embedded_list_read_delimit_mode_depth_greater) { + if (data.delimit_depth >= data.nest.used) { + objects_delimits->used = 0; + contents_delimits->used = 0; + return; + } + } + + const f_string_length_t original_objects_used = objects_delimits->used; + const f_string_length_t original_contents_used = contents_delimits->used; + + f_string_length_t original_objects_delimits[original_objects_used]; + f_string_length_t original_contents_delimits[original_contents_used]; + + memcpy(&original_objects_delimits, objects_delimits->array, original_objects_used * sizeof(f_string_length_t)); + memcpy(&original_contents_delimits, contents_delimits->array, original_contents_used * sizeof(f_string_length_t)); + + objects_delimits->used = 0; + contents_delimits->used = 0; + + if (data.delimit_mode == fss_embedded_list_read_delimit_mode_depth) { + + // only depth 0 objects are stored in objects_delimits. + if (data.delimit_depth) { + fss_embedded_list_read_process_delimits_objects(data, data.delimit_depth, original_contents_delimits, original_contents_used, contents_delimits); + } + else { + fss_embedded_list_read_process_delimits_objects(data, data.delimit_depth, original_objects_delimits, original_objects_used, objects_delimits); + } + + fss_embedded_list_read_process_delimits_contents(data, data.delimit_depth, original_contents_delimits, original_contents_used, contents_delimits); + } + else { + + if (data.delimit_mode == fss_embedded_list_read_delimit_mode_depth_lesser) { + + // only depth 0 objects are stored in objects_delimits. + fss_embedded_list_read_process_delimits_objects(data, 0, original_objects_delimits, original_objects_used, objects_delimits); + fss_embedded_list_read_process_delimits_contents(data, 0, original_contents_delimits, original_contents_used, contents_delimits); + + for (f_array_length_t i = 1; i <= data.delimit_depth && i < data.nest.used; ++i) { + + fss_embedded_list_read_process_delimits_objects(data, i, original_contents_delimits, original_contents_used, contents_delimits); + fss_embedded_list_read_process_delimits_contents(data, i, original_contents_delimits, original_contents_used, contents_delimits); + } // for + } + else if (data.delimit_mode == fss_embedded_list_read_delimit_mode_depth_greater) { + for (f_array_length_t i = data.delimit_depth; i < data.nest.used; ++i) { + + fss_embedded_list_read_process_delimits_objects(data, i, original_contents_delimits, original_contents_used, contents_delimits); + fss_embedded_list_read_process_delimits_contents(data, i, original_contents_delimits, original_contents_used, contents_delimits); + } // for + } + } + } +#endif // _di_fss_embedded_list_read_process_delimits_ + +#ifndef _di_fss_embedded_list_read_process_delimits_contents_ + void fss_embedded_list_read_process_delimits_contents(const fss_embedded_list_read_data_t data, const f_string_length_t depth, const f_string_length_t original_delimits[], const f_string_length_t original_used, f_fss_delimits_t *delimits) { + + if (!original_used) return; + + f_fss_items_t *items = &data.nest.depth[depth]; + + if (!items->used) return; + + f_array_length_t i = 0; + f_array_length_t j = 0; + f_array_length_t k = 0; + f_array_length_t l = 0; + f_array_length_t m = 0; + + for (i = 0; i < items->used; ++i) { + + for (j = 0; j < original_used; ++j) { + + for (k = 0; k < items->array[i].content.used; ++k) { + + if (original_delimits[j] >= items->array[i].content.array[k].start && original_delimits[j] <= items->array[i].content.array[k].stop) { + + // preserve linear order when adding back delimits. + if (delimits->used) { + for (l = 0; l < delimits->used; ++l) { + + if (original_delimits[j] > delimits->array[l]) continue; + if (original_delimits[j] == delimits->array[l]) break; + + for (m = delimits->used; m > l; --m) { + delimits->array[m] = delimits->array[m - 1]; + } // for + + if (fss_embedded_list_read_process_delimits_within_greater(data, depth, original_delimits[j]) == F_false) { + delimits->array[l] = original_delimits[j]; + delimits->used++; + } + + break; + } // for + } + else if (fss_embedded_list_read_process_delimits_within_greater(data, depth, original_delimits[j]) == F_false) { + delimits->array[0] = original_delimits[j]; + delimits->used = 1; + } + } + } + } // for + } // for + } +#endif // _di_fss_embedded_list_read_process_delimits_contents_ + +#ifndef _di_fss_embedded_list_read_process_delimits_objects_ + void fss_embedded_list_read_process_delimits_objects(const fss_embedded_list_read_data_t data, const f_string_length_t depth, const f_string_length_t original_delimits[], const f_string_length_t original_used, f_fss_delimits_t *delimits) { + + if (!original_used) return; + + f_fss_items_t *items = &data.nest.depth[depth]; + + if (!items->used) return; + + f_array_length_t i = 0; + f_array_length_t j = 0; + f_array_length_t k = 0; + f_array_length_t l = 0; + + for (i = 0; i < items->used; ++i) { + + for (j = 0; j < original_used; ++j) { + + if (original_delimits[j] >= items->array[i].object.start && original_delimits[j] <= items->array[i].object.stop) { + + // preserve linear order when adding back delimits. + if (delimits->used) { + for (k = 0; k < delimits->used; ++k) { + + if (original_delimits[j] > delimits->array[k]) continue; + if (original_delimits[j] == delimits->array[k]) break; + + for (l = delimits->used; l > k; --l) { + delimits->array[l] = delimits->array[l - 1]; + } // for + + if (fss_embedded_list_read_process_delimits_within_greater(data, depth, original_delimits[j]) == F_false) { + delimits->array[k] = original_delimits[j]; + delimits->used++; + } + + break; + } // for + } + else if (fss_embedded_list_read_process_delimits_within_greater(data, depth, original_delimits[j]) == F_false) { + delimits->array[0] = original_delimits[j]; + delimits->used = 1; + } + } + } // for + } // for + } +#endif // _di_fss_embedded_list_read_process_delimits_objects_ + +#ifndef _di_fss_embedded_list_read_process_delimits_within_greater_ + f_return_status fss_embedded_list_read_process_delimits_within_greater(const fss_embedded_list_read_data_t data, const f_string_length_t depth, const f_string_length_t location) { + + if (depth + 1 >= data.nest.used) return F_false; + + f_fss_items_t *items = 0; + + f_string_length_t i = 0; + f_string_length_t j = 0; + + for (f_string_length_t d = depth + 1; d < data.nest.used; ++d) { + items = &data.nest.depth[d]; + + for (i = 0; i < items->used; ++i) { + + for (j = 0; j < items->array[i].content.used; ++j) { + + if (location >= items->array[i].content.array[j].start && location <= items->array[i].content.array[j].stop) { + return F_true; + } + } // for + } // for + } // for + + return F_false; + } +#endif // _di_fss_embedded_list_read_process_delimits_within_greater_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_3/fss_embedded_list_read/c/private-fss_embedded_list_read.h b/level_3/fss_embedded_list_read/c/private-fss_embedded_list_read.h new file mode 100644 index 0000000..b810059 --- /dev/null +++ b/level_3/fss_embedded_list_read/c/private-fss_embedded_list_read.h @@ -0,0 +1,396 @@ +/** + * FLL - Level 3 + * + * Project: FSS + * API Version: 0.5 + * Licenses: lgplv2.1 + */ +#ifndef _PRIVATE_fss_embedded_list_read_h +#define _PRIVATE_fss_embedded_list_read_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A structure of parameters applied at some depth. + * + * depth: the depth number in which this is to be processed at. + * + * index_at: position of the "--at" parameter value in the argv list, when 0 there is no parameter. + * index_name: position of the "--name" parameter value in the argv list, when 0 there is no parameter. + * + * value_at: the value of the "--at" parameter, already processed and ready to use, only when index_at > 0. + * value_name: the value of the "--name" parameter, already processed and ready to use, only when index_name > 0. + */ +#ifndef _di_fss_embedded_list_read_depth_t_ + typedef struct { + f_string_length_t depth; + + f_array_length_t index_at; + f_array_length_t index_name; + + f_number_unsigned_t value_at; + f_string_dynamic_t value_name; + } fss_embedded_list_read_depth_t; + + #define fss_embedded_list_read_depth_t_initialize \ + { \ + 0, \ + 0, \ + 0, \ + 0, \ + f_string_dynamic_t_initialize, \ + } + + #define macro_fss_embedded_list_read_depth_t_clear(structure) \ + structure.depth = 0; \ + structure.index_at = 0; \ + structure.index_name = 0; \ + structure.value_at = 0; \ + f_macro_string_dynamic_t_clear(structure.value_name) + + #define macro_fss_embedded_list_read_depth_t_delete(status, structure) f_macro_string_dynamic_t_delete(status, structure.value_name) + #define macro_fss_embedded_list_read_depth_t_destroy(status, structure) f_macro_string_dynamic_t_destroy(status, structure.value_name) + + #define macro_fss_embedded_list_read_depth_t_delete_simple(structure) f_macro_string_dynamic_t_delete_simple(structure.value_name) + #define macro_fss_embedded_list_read_depth_t_destroy_simple(structure) f_macro_string_dynamic_t_destroy_simple(structure.value_name) +#endif // _di_fss_embedded_list_read_depth_t_ + +/** + * A structure containing a statically allocated array of booleans and the array length. + * + * skip: a statically allocated array representing list items that are to be skipped. + * used: the length of the statically allocated skip array. + */ +#ifndef _di_fss_embedded_list_read_skip_t_ + typedef struct { + bool *skip; + f_array_length_t used; + } fss_embedded_list_read_skip_t; + + #define fss_embedded_list_read_skip_t_initialize \ + { \ + 0, \ + 0, \ + } + + #define macro_fss_embedded_list_read_skip_t_initialize(skip, used) \ + { \ + skip, \ + used, \ + } +#endif // _di_fss_embedded_list_read_skip_t_ + +/** + * An array of depth parameters. + * + * array: the array of depths. + * size: total amount of allocated space. + * used: total number of allocated spaces used. + */ +#ifndef _di_fss_embedded_list_read_depths_t_ + typedef struct { + fss_embedded_list_read_depth_t *array; + + f_array_length_t size; + f_array_length_t used; + } fss_embedded_list_read_depths_t; + + #define fss_embedded_list_read_depths_t_initialize { 0, 0, 0 } + + #define macro_fss_embedded_list_read_depths_t_clear(depths) f_macro_memory_structure_t_clear(depths) + + #define macro_fss_embedded_list_read_depths_t_new(status, depths, length) f_macro_memory_structure_t_new(status, depths, fss_embedded_list_read_depth_t, length) + + #define macro_fss_embedded_list_read_depths_t_delete(status, depths) \ + status = F_none; \ + depths.used = depths.size; \ + while (depths.used > 0) { \ + depths.used--; \ + macro_fss_embedded_list_read_depth_t_delete(status, depths.array[depths.used]); \ + if (status != F_none) break; \ + } \ + if (status == F_none) f_macro_memory_structure_t_delete(depths, fss_embedded_list_read_depth_t) + + #define macro_fss_embedded_list_read_depths_t_destroy(status, depths) \ + status = F_none; \ + depths.used = depths.size; \ + while (depths.used > 0) { \ + depths.used--; \ + macro_fss_embedded_list_read_depth_t_destroy(status, depths.array[depths.used]); \ + if (status != F_none) break; \ + } \ + if (status == F_none) f_macro_memory_structure_t_destroy(depths, fss_embedded_list_read_depth_t) + + #define macro_fss_embedded_list_read_depths_t_delete_simple(depths) \ + depths.used = depths.size; \ + while (depths.used > 0) { \ + depths.used--; \ + macro_fss_embedded_list_read_depth_t_delete_simple(depths.array[depths.used]); \ + } \ + if (!depths.used) f_macro_memory_structure_t_delete_simple(depths, fss_embedded_list_read_depth_t) + + #define macro_fss_embedded_list_read_depths_t_destroy_simple(depths) \ + depths.used = depths.size; \ + while (depths.used > 0) { \ + depths.used--; \ + macro_fss_embedded_list_read_depth_t_destroy_simple(depths.array[depths.used]); \ + } \ + if (!depths.used) f_macro_memory_structure_t_destroy_simple(depths, fss_embedded_list_read_depth_t) + + #define macro_fss_embedded_list_read_t_depths_resize(status, depths, new_length) \ + status = F_none; \ + if (new_length < depths.size) { \ + f_array_length_t i = depths.size - new_length; \ + for (; i < depths.size; i++) { \ + macro_fss_embedded_list_read_depth_t_delete(status, depths.array[i]); \ + if (status != F_none) break; \ + } \ + } \ + if (status == F_none) status = f_memory_resize((void **) & depths.array, sizeof(fss_embedded_list_read_depth_t), depths.size, new_length); \ + if (status == F_none) { \ + if (new_length > depths.size) { \ + f_array_length_t i = depths.size; \ + for (; i < new_length; i++) { \ + memset(&depths.array[i], 0, sizeof(fss_embedded_list_read_depth_t)); \ + } \ + } \ + depths.size = new_length; \ + if (depths.used > depths.size) depths.used = new_length; \ + } + + #define macro_fss_embedded_list_read_depths_t_adjust(status, depths, new_length) \ + status = F_none; \ + if (new_length < depths.size) { \ + f_array_length_t i = depths.size - new_length; \ + for (; i < depths.size; i++) { \ + macro_fss_embedded_list_read_depth_t_delete(status, depths.array[i]); \ + if (status != F_none) break; \ + } \ + } \ + if (status == F_none) status = f_memory_adjust((void **) & depths.array, sizeof(fss_embedded_list_read_depth_t), depths.size, new_length); \ + if (status == F_none) { \ + if (new_length > depths.size) { \ + f_array_length_t i = depths.size; \ + for (; i < new_length; i++) { \ + memset(&depths.array[i], 0, sizeof(fss_embedded_list_read_depth_t)); \ + } \ + } \ + depths.size = new_length; \ + if (depths.used > depths.size) depths.used = new_length; \ + } +#endif // _di_fss_embedded_list_read_depths_t_ + +/** + * Pre-process the parameters, parsing out and handling the depth and depth related parameters. + * + * Will handle depth-sensitive parameter conflicts, such as --name being used with --at (which is not allowed). + * + * @param arguments + * The console arguments to pre-process. + * @param data + * The program specific data. + * @param depths + * This stores the pre-processed depth parameters. + * + * @return + * F_none on success. + * + * Status codes (with error bit) are returned on any problem. + */ +#ifndef _di_fss_embedded_list_read_main_preprocess_depth_ + extern f_return_status fss_embedded_list_read_main_preprocess_depth(const f_console_arguments_t arguments, const fss_embedded_list_read_data_t data, fss_embedded_list_read_depths_t *depths) f_gcc_attribute_visibility_internal; +#endif // _di_fss_embedded_list_read_main_preprocess_depth_ + +/** + * Process a given file. + * + * @param arguments + * The console arguments passed to the program. + * @param data + * The program specific data. + * @param file_name + * The name of the file being processed. + * @param depths + * The processed depth parameters. + * @param objects_delimits + * An array of delimits detected during processing, for top-level objects. + * @param contents_delimits + * An array of delimits detected during processing, for contents. + * @param comments + * An array of ranges representing where comments are found within any valid content. + * This only stores comments found within valid content only. + * + * @see fss_embedded_list_read_main_preprocess_depth() + * @see fss_embedded_list_read_main_process_for_depth() + * + * @return + * F_none on success. + * + * Status codes (with error bit) are returned on any problem. + */ +#ifndef _di_fss_embedded_list_read_main_process_file_ + extern f_return_status fss_embedded_list_read_main_process_file(const f_console_arguments_t arguments, fss_embedded_list_read_data_t *data, const f_string_t file_name, const fss_embedded_list_read_depths_t depths, f_fss_delimits_t *objects_delimits, f_fss_delimits_t *contents_delimits, f_fss_comments_t *comments) f_gcc_attribute_visibility_internal; +#endif // _di_fss_embedded_list_read_main_process_file_ + +/** + * Process the items for a given depth. + * + * This will recursively continue down the depth chain until the final depth is reached. + * + * @param arguments + * The console arguments passed to the program. + * @param file_name + * The name of the file being processed. + * @param depths + * The array of all depth related parameter settings. + * @param depths_index + * The array location within depth being worked on. + * @param line + * The line number parameter value, used for printing a specific line number for content. + * @param parents + * The skip status of any parent lists. + * Set parents.length to 0 for depth 0. + * @param data + * The program specific data. + * @param objects_delimits + * An array of delimits detected during processing, for top-level objects. + * @param contents_delimits + * An array of delimits detected during processing, for contents. + * + * @return + * F_none on success. + * + * Status codes (with error bit) are returned on any problem. + * + * @see fss_embedded_list_read_main_process_file() + */ +#ifndef _di_fss_embedded_list_read_main_process_for_depth_ + extern f_return_status fss_embedded_list_read_main_process_for_depth(const f_console_arguments_t arguments, const f_string_t filename, const fss_embedded_list_read_depths_t depths, const f_array_length_t depths_index, const f_array_length_t line, const fss_embedded_list_read_skip_t parents, fss_embedded_list_read_data_t *data, f_fss_delimits_t *objects_delimits, f_fss_delimits_t *contents_delimits) f_gcc_attribute_visibility_internal; +#endif // _di_fss_embedded_list_read_main_process_for_depth_ + +/** + * Print the end of an content. + * + * @param data + * The program specific data. + */ +#ifndef _di_fss_embedded_list_read_print_content_end_ + extern void fss_embedded_list_read_print_content_end(const fss_embedded_list_read_data_t data) f_gcc_attribute_visibility_internal; +#endif // _di_fss_embedded_list_read_print_content_end_ + +/** + * Print the ignore character for content. + * + * This is only used in pipe output mode. + * + * @param data + * The program specific data. + */ +#ifndef _di_fss_embedded_list_read_print_content_ignore_ + extern void fss_embedded_list_read_print_content_ignore(const fss_embedded_list_read_data_t data) f_gcc_attribute_visibility_internal; +#endif // _di_fss_embedded_list_read_print_content_ignore_ + +/** + * Print the end of an object (which is essentially the start of a content). + * + * @param data + * The program specific data. + */ +#ifndef _di_fss_embedded_list_read_print_object_end_ + extern void fss_embedded_list_read_print_object_end(const fss_embedded_list_read_data_t data) f_gcc_attribute_visibility_internal; +#endif // _di_fss_embedded_list_read_print_object_end_ + +/** + * Print the end of an object/content set. + * + * @param data + * The program specific data. + */ +#ifndef _di_fss_embedded_list_read_print_set_end_ + extern void fss_embedded_list_read_print_set_end(const fss_embedded_list_read_data_t data) f_gcc_attribute_visibility_internal; +#endif // _di_fss_embedded_list_read_print_set_end_ + +/** + * Rewrite the object and content delimit ranges to be within the given depth range. + * + * @param data + * The program specific data. + * @param objects_delimits + * An array of delimits detected during processing, for top-level objects. + * @param contents_delimits + * An array of delimits detected during processing, for contents. + * + * @see fss_embedded_list_read_main_process_file() + */ +#ifndef _di_fss_embedded_list_read_process_delimits_ + extern void fss_embedded_list_read_process_delimits(const fss_embedded_list_read_data_t data, f_fss_delimits_t *objects_delimits, f_fss_delimits_t *contents_delimits) f_gcc_attribute_visibility_internal; +#endif // _di_fss_embedded_list_read_process_delimits_ + +/** + * Write the given delimits at the given depth back into the new delimits array, specifically for contents. + * + * @param data + * The program specific data. + * @param depth + * The depth in which to process. + * @param original_delimits + * The original delimits structure. + * @param original_used + * The size of the original delimits structure. + * @param delimits + * The delimits array in which the delimits are written to. + * + * @see fss_embedded_list_read_process_delimits() + */ +#ifndef _di_fss_embedded_list_read_process_delimits_contents_ + extern void fss_embedded_list_read_process_delimits_contents(const fss_embedded_list_read_data_t data, const f_string_length_t depth, const f_string_length_t original_delimits[], const f_string_length_t original_used, f_fss_delimits_t *delimits) f_gcc_attribute_visibility_internal; +#endif // _di_fss_embedded_list_read_process_delimits_contents_ + +/** + * Write the given delimits at the given depth back into the new delimits array, specifically for objects. + * + * @param data + * The program specific data. + * @param depth + * The depth in which to process. + * @param original_delimits + * The original delimits structure. + * @param original_used + * The size of the original delimits structure. + * @param delimits + * The delimits array in which the delimits are written to. + * + * @see fss_embedded_list_read_process_delimits() + */ +#ifndef _di_fss_embedded_list_read_process_delimits_objects_ + extern void fss_embedded_list_read_process_delimits_objects(const fss_embedded_list_read_data_t data, const f_string_length_t depth, const f_string_length_t original_delimits[], const f_string_length_t original_used, f_fss_delimits_t *delimits) f_gcc_attribute_visibility_internal; +#endif // _di_fss_embedded_list_read_process_delimits_objects_ + +/** + * Determine if the given location is actually within another depth. + * + * @param data + * The program specific data. + * @param depth + * The depth in which to process. + * @param location + * The location to investigate. + * + * @return + * TRUE if location is within a greater depth. + * FALSE if location is not within a greater depth. + * + * @see fss_embedded_list_read_process_delimits_objects() + * @see fss_embedded_list_read_process_delimits_contents() + */ +#ifndef _di_fss_embedded_list_read_process_delimits_within_greater_ + extern f_return_status fss_embedded_list_read_process_delimits_within_greater(const fss_embedded_list_read_data_t data, const f_string_length_t depth, const f_string_length_t location) f_gcc_attribute_visibility_internal; +#endif // _di_fss_embedded_list_read_process_delimits_within_greater_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _PRIVATE_fss_embedded_list_read_h diff --git a/level_3/fss_embedded_list_read/data/build/defines b/level_3/fss_embedded_list_read/data/build/defines new file mode 100644 index 0000000..c665317 --- /dev/null +++ b/level_3/fss_embedded_list_read/data/build/defines @@ -0,0 +1,2 @@ +# fss-0000 + diff --git a/level_3/fss_embedded_list_read/data/build/dependencies b/level_3/fss_embedded_list_read/data/build/dependencies new file mode 100644 index 0000000..4f23c89 --- /dev/null +++ b/level_3/fss_embedded_list_read/data/build/dependencies @@ -0,0 +1,27 @@ +# 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_print +fl_status +fl_string +fll_error +fll_execute +fll_file +fll_fss +fll_program diff --git a/level_3/fss_embedded_list_read/data/build/settings b/level_3/fss_embedded_list_read/data/build/settings new file mode 100644 index 0000000..fd9b43c --- /dev/null +++ b/level_3/fss_embedded_list_read/data/build/settings @@ -0,0 +1,57 @@ +# fss-0001 + +project_name fss_embedded_list_read + +version_major 0 +version_minor 5 +version_micro 2 +version_target major + +environment + +process_pre +process_post + +modes individual level monolithic +modes_default monolithic + +build_compiler gcc +build_indexer ar +build_language c +build_libraries -lc +build_libraries-individual -lfll_error -lfll_execute -lfll_file -lfll_fss -lfll_program -lfl_color -lfl_console -lfl_conversion -lfl_directory -lfl_environment -lfl_fss -lfl_print -lfl_status -lfl_string -lf_console -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_utf +build_libraries-level -lfll_2 -lfll_1 -lfll_0 +build_libraries-monolithic -lfll +build_sources_library fss_embedded_list_read.c private-fss_embedded_list_read.c +build_sources_program main.c +build_sources_headers fss_embedded_list_read.h +build_sources_script +build_sources_setting +build_script yes +build_shared yes +build_static yes + +path_headers level_3 +path_headers_preserve no +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_embedded_list_write/c/fss_embedded_list_write.c b/level_3/fss_embedded_list_write/c/fss_embedded_list_write.c new file mode 100644 index 0000000..dae753a --- /dev/null +++ b/level_3/fss_embedded_list_write/c/fss_embedded_list_write.c @@ -0,0 +1,529 @@ +#include "fss_embedded_list_write.h" +#include "private-fss_embedded_list_write.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fss_embedded_list_write_print_help_ + f_return_status fss_embedded_list_write_print_help(const f_file_t output, const f_color_context_t context) { + + fll_program_print_help_header(output, context, fss_embedded_list_write_name_long, fss_embedded_list_write_version); + + fll_program_print_help_option(output, 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(output, 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(output, 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(output, 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(output, 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(output, 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(output, 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(output, 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(output, 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."); + + fprintf(output.stream, "%c", f_string_eol[0]); + + fll_program_print_help_option(output, context, fss_embedded_list_write_short_file, fss_embedded_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(output, context, fss_embedded_list_write_short_content, fss_embedded_list_write_long_content, f_console_symbol_short_enable, f_console_symbol_long_enable, "The Content to output."); + fll_program_print_help_option(output, context, fss_embedded_list_write_short_double, fss_embedded_list_write_long_double, f_console_symbol_short_enable, f_console_symbol_long_enable, " Use double quotes (default)."); + fll_program_print_help_option(output, context, fss_embedded_list_write_short_ignore, fss_embedded_list_write_long_ignore, f_console_symbol_short_enable, f_console_symbol_long_enable, " Ignore a given range within a content."); + fll_program_print_help_option(output, context, fss_embedded_list_write_short_object, fss_embedded_list_write_long_object, f_console_symbol_short_enable, f_console_symbol_long_enable, " The Object to output."); + fll_program_print_help_option(output, context, fss_embedded_list_write_short_partial, fss_embedded_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(output, context, fss_embedded_list_write_short_prepend, fss_embedded_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(output, context, fss_embedded_list_write_short_single, fss_embedded_list_write_long_single, f_console_symbol_short_enable, f_console_symbol_long_enable, " Use single quotes."); + fll_program_print_help_option(output, context, fss_embedded_list_write_short_trim, fss_embedded_list_write_long_trim, f_console_symbol_short_enable, f_console_symbol_long_enable, " Trim object names."); + + fll_program_print_help_usage(output, context, fss_embedded_list_write_name, ""); + + fprintf(output.stream, " The pipe uses the Backspace character '"); + fl_color_print(output.stream, context.set.notable, "\\b"); + fprintf(output.stream, "' ("); + fl_color_print(output.stream, context.set.notable, "U+0008"); + fprintf(output.stream, ") to designate the start of a Content.%c", f_string_eol[0]); + + fprintf(output.stream, " The pipe uses the Form Feed character '"); + fl_color_print(output.stream, context.set.notable, "\\f"); + fprintf(output.stream, "' ("); + fl_color_print(output.stream, context.set.notable, "U+000C"); + fprintf(output.stream, ") to designate the end of the last Content.%c", f_string_eol[0]); + + fprintf(output.stream, " The pipe uses the Vertical Line character '"); + fl_color_print(output.stream, context.set.notable, "\\v"); + fprintf(output.stream, "' ("); + fl_color_print(output.stream, context.set.notable, "U+000B"); + fprintf(output.stream, ") is used to ignore a content range (use this both before and after the range).%c", f_string_eol[0]); + + fprintf(output.stream, " For the pipe, an Object is terminated by either a Backspace character '"); + fl_color_print(output.stream, context.set.notable, "\\b"); + fprintf(output.stream, "' ("); + fl_color_print(output.stream, context.set.notable, "U+0008"); + fprintf(output.stream, ") or a Form Feed character '"); + fl_color_print(output.stream, context.set.notable, "\\f"); + fprintf(output.stream, "' ("); + fl_color_print(output.stream, context.set.notable, "U+000C"); + fprintf(output.stream, ").%c", f_string_eol[0]); + + fprintf(output.stream, " The end of the pipe represents the end of any Object or Content.%c", f_string_eol[0]); + + fprintf(output.stream, "%c", f_string_eol[0]); + + fprintf(output.stream, " The FSS-0008 (Embedded List) specification does not support quoted names, therefore the parameters '"); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_write_long_single); + fprintf(output.stream, "' and '"); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_write_long_double); + fprintf(output.stream, "' do nothing.%c", f_string_eol[0]); + + fprintf(output.stream, "%c", f_string_eol[0]); + + fprintf(output.stream, " The parameter '"); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_write_long_ignore); + fprintf(output.stream, "' designates to not escape any valid nested Object or Content within some Content.%c", f_string_eol[0]); + fprintf(output.stream, " This parameter requires two values.%c", f_string_eol[0]); + fprintf(output.stream, " This parameter is not used for ignoring anything from the input pipe.%c", f_string_eol[0]); + fprintf(output.stream, " This parameter must be specified after a '"); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_write_long_content); + fprintf(output.stream, "' parameter and this applies only to the Content represented by that specific '"); + fl_color_print(output.stream, context.set.notable, "%s%s", f_console_symbol_long_enable, fss_embedded_list_write_long_content); + fprintf(output.stream, "' parameter.%c", f_string_eol[0]); + + fprintf(output.stream, "%c", f_string_eol[0]); + + return F_none; + } +#endif // _di_fss_embedded_list_write_print_help_ + +#ifndef _di_fss_embedded_list_write_main_ + f_return_status fss_embedded_list_write_main(const f_console_arguments_t arguments, fss_embedded_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_embedded_list_write_total_parameters); + + { + f_console_parameter_id_t ids[3] = { fss_embedded_list_write_parameter_no_color, fss_embedded_list_write_parameter_light, fss_embedded_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_embedded_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_embedded_list_write_parameter_verbosity_quiet, fss_embedded_list_write_parameter_verbosity_normal, fss_embedded_list_write_parameter_verbosity_verbose, fss_embedded_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_embedded_list_write_delete_data(data); + return status; + } + + if (choice == fss_embedded_list_write_parameter_verbosity_quiet) { + data->error.verbosity = f_console_verbosity_quiet; + } + else if (choice == fss_embedded_list_write_parameter_verbosity_normal) { + data->error.verbosity = f_console_verbosity_normal; + } + else if (choice == fss_embedded_list_write_parameter_verbosity_verbose) { + data->error.verbosity = f_console_verbosity_verbose; + } + else if (choice == fss_embedded_list_write_parameter_verbosity_debug) { + data->error.verbosity = f_console_verbosity_debug; + } + } + + status = F_none; + } + + if (data->parameters[fss_embedded_list_write_parameter_help].result == f_console_result_found) { + fss_embedded_list_write_print_help(data->output, data->context); + + fss_embedded_list_write_delete_data(data); + return status; + } + + if (data->parameters[fss_embedded_list_write_parameter_version].result == f_console_result_found) { + fll_program_print_version(data->output, fss_embedded_list_write_version); + + fss_embedded_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_embedded_list_write_parameter_file].result == f_console_result_additional) { + if (data->parameters[fss_embedded_list_write_parameter_file].values.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_embedded_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_embedded_list_write_parameter_file].values.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_embedded_list_write_parameter_file].result == f_console_result_found) { + fss_embedded_list_write_error_parameter_value_missing_print(*data, f_console_symbol_long_enable, fss_embedded_list_write_long_file); + status = F_status_set_error(F_parameter); + } + } + + if (F_status_is_error_not(status)) { + if (data->parameters[fss_embedded_list_write_parameter_object].locations.used || data->parameters[fss_embedded_list_write_parameter_content].locations.used) { + if (data->parameters[fss_embedded_list_write_parameter_object].locations.used) { + if (data->parameters[fss_embedded_list_write_parameter_object].locations.used != data->parameters[fss_embedded_list_write_parameter_object].values.used) { + fss_embedded_list_write_error_parameter_value_missing_print(*data, f_console_symbol_long_enable, fss_embedded_list_write_long_object); + status = F_status_set_error(F_parameter); + } + else if (data->parameters[fss_embedded_list_write_parameter_content].locations.used != data->parameters[fss_embedded_list_write_parameter_content].values.used) { + fss_embedded_list_write_error_parameter_value_missing_print(*data, f_console_symbol_long_enable, fss_embedded_list_write_long_content); + status = F_status_set_error(F_parameter); + } + else if (data->parameters[fss_embedded_list_write_parameter_object].locations.used != data->parameters[fss_embedded_list_write_parameter_content].locations.used && data->parameters[fss_embedded_list_write_parameter_partial].result == f_console_result_none) { + fss_embedded_list_write_error_parameter_same_times_print(*data); + status = F_status_set_error(F_parameter); + } + else if (data->parameters[fss_embedded_list_write_parameter_content].locations.used && data->parameters[fss_embedded_list_write_parameter_partial].locations.used) { + if (data->parameters[fss_embedded_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_embedded_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_embedded_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_embedded_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_embedded_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_embedded_list_write_parameter_object].locations.used; i++) { + location_object = data->parameters[fss_embedded_list_write_parameter_object].locations.array[i]; + location_content = data->parameters[fss_embedded_list_write_parameter_content].locations.array[i]; + location_sub_object = data->parameters[fss_embedded_list_write_parameter_object].locations_sub.array[i]; + location_sub_content = data->parameters[fss_embedded_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_embedded_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_embedded_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_embedded_list_write_parameter_content].locations.used) { + if (data->parameters[fss_embedded_list_write_parameter_content].locations.used != data->parameters[fss_embedded_list_write_parameter_content].values.used) { + fss_embedded_list_write_error_parameter_value_missing_print(*data, f_console_symbol_long_enable, fss_embedded_list_write_long_content); + status = F_status_set_error(F_parameter); + } + else if (!data->parameters[fss_embedded_list_write_parameter_partial].locations.used) { + fss_embedded_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_embedded_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_embedded_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_embedded_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_embedded_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_embedded_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_embedded_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_embedded_list_write_parameter_prepend].result == f_console_result_additional) { + const f_string_length_t index = data->parameters[fss_embedded_list_write_parameter_prepend].values.array[data->parameters[fss_embedded_list_write_parameter_prepend].values.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_embedded_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_embedded_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); + } + } + } + + if (F_status_is_error_not(status)) { + if (data->parameters[fss_embedded_list_write_parameter_ignore].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_embedded_list_write_long_ignore); + fl_color_print(data->error.to.stream, data->context.set.error, "' was specified, but no values were given.%c", f_string_eol[0]); + } + + status = F_status_set_error(F_parameter); + } + else if (data->parameters[fss_embedded_list_write_parameter_ignore].result == f_console_result_additional) { + const f_array_length_t total_locations = data->parameters[fss_embedded_list_write_parameter_ignore].locations.used; + const f_array_length_t total_arguments = data->parameters[fss_embedded_list_write_parameter_ignore].values.used; + + if (total_locations * 2 > total_arguments) { + 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_embedded_list_write_long_ignore); + fl_color_print(data->error.to.stream, data->context.set.error, "' requires two values.%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_embedded_list_write_parameter_double].result == f_console_result_found) { + if (data->parameters[fss_embedded_list_write_parameter_single].result == f_console_result_found) { + if (data->parameters[fss_embedded_list_write_parameter_double].location < data->parameters[fss_embedded_list_write_parameter_single].location) { + quote = f_fss_delimit_quote_single; + } + } + } + else if (data->parameters[fss_embedded_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; + f_string_ranges_t ignore = f_string_ranges_t_initialize; + + if (data->process_pipe) { + status = fss_embedded_list_write_process_pipe(*data, output, quote, &buffer, &ignore); + + 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]); + } + } + + ignore.used = 0; + } + + if (F_status_is_error_not(status)) { + if (data->parameters[fss_embedded_list_write_parameter_partial].result == f_console_result_found) { + + if (data->parameters[fss_embedded_list_write_parameter_object].result == f_console_result_additional) { + for (f_array_length_t i = 0; i < data->parameters[fss_embedded_list_write_parameter_object].values.used; i++) { + + object.string = arguments.argv[data->parameters[fss_embedded_list_write_parameter_object].values.array[i]]; + object.used = strnlen(object.string, f_console_length_size); + object.size = object.used; + + status = fss_embedded_list_write_process(*data, output, quote, &object, 0, 0, &buffer); + if (F_status_is_error(status)) break; + } // for + } + else { + for (f_array_length_t i = 0; i < data->parameters[fss_embedded_list_write_parameter_content].values.used; i++) { + + status = fss_embedded_list_write_process_parameter_ignore(arguments, *data, data->parameters[fss_embedded_list_write_parameter_content].locations, i, &ignore); + if (F_status_is_error(status)) break; + + content.string = arguments.argv[data->parameters[fss_embedded_list_write_parameter_content].values.array[i]]; + content.used = strnlen(content.string, f_console_length_size); + content.size = content.used; + + status = fss_embedded_list_write_process(*data, output, quote, 0, &content, &ignore, &buffer); + if (F_status_is_error(status)) break; + } // for + } + } + else { + for (f_array_length_t i = 0; i < data->parameters[fss_embedded_list_write_parameter_object].values.used; i++) { + + status = fss_embedded_list_write_process_parameter_ignore(arguments, *data, data->parameters[fss_embedded_list_write_parameter_content].locations, i, &ignore); + if (F_status_is_error(status)) break; + + object.string = arguments.argv[data->parameters[fss_embedded_list_write_parameter_object].values.array[i]]; + object.used = strnlen(object.string, f_console_length_size); + object.size = object.used; + + content.string = arguments.argv[data->parameters[fss_embedded_list_write_parameter_content].values.array[i]]; + content.used = strnlen(content.string, f_console_length_size); + content.size = content.used; + + status = fss_embedded_list_write_process(*data, output, quote, &object, &content, &ignore, &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_embedded_list_write_parameter_file].result == f_console_result_none) { + + // ensure there is always a newline at the end, unless in quiet mode. + fprintf(data->output.stream, "%c", f_string_eol[0]); + } + } + + f_macro_string_dynamic_t_delete_simple(escaped); + f_macro_string_ranges_t_delete_simple(ignore); + + // 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_embedded_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_embedded_list_write_delete_data(data); + return status; + } +#endif // _di_fss_embedded_list_write_main_ + +#ifndef _di_fss_embedded_list_write_delete_data_ + f_return_status fss_embedded_list_write_delete_data(fss_embedded_list_write_data_t *data) { + + for (f_string_length_t i = 0; i < fss_embedded_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].values); + } // 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_embedded_list_write_delete_data_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_3/fss_embedded_list_write/c/fss_embedded_list_write.h b/level_3/fss_embedded_list_write/c/fss_embedded_list_write.h new file mode 100644 index 0000000..c3df671 --- /dev/null +++ b/level_3/fss_embedded_list_write/c/fss_embedded_list_write.h @@ -0,0 +1,214 @@ +/** + * FLL - Level 3 + * + * Project: FSS + * API Version: 0.5 + * Licenses: lgplv2.1 + * + * This program provides FSS-0008 Embedded List write functionality. + */ +#ifndef _fss_embedded_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 +#include + +// fll-2 includes +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fss_embedded_list_write_version_ + #define fss_embedded_list_write_major_version "0" + #define fss_embedded_list_write_minor_version "5" + #define fss_embedded_list_write_micro_version "2" + #define fss_embedded_list_write_version fss_embedded_list_write_major_version "." fss_embedded_list_write_minor_version "." fss_embedded_list_write_micro_version +#endif // _di_fss_embedded_list_write_version_ + +#ifndef _di_fss_embedded_list_write_name_ + #define fss_embedded_list_write_name "fss_embedded_list_write" + #define fss_embedded_list_write_name_long "FSS Embedded List Write" +#endif // _di_fss_embedded_list_write_name_ + +#ifndef _di_fss_embedded_list_write_defines_ + #define fss_embedded_list_write_pipe_content_end '\f' + #define fss_embedded_list_write_pipe_content_ignore '\v' + #define fss_embedded_list_write_pipe_content_start '\b' + + #define fss_embedded_list_write_short_file "f" + #define fss_embedded_list_write_short_content "c" + #define fss_embedded_list_write_short_double "d" + #define fss_embedded_list_write_short_ignore "I" + #define fss_embedded_list_write_short_object "o" + #define fss_embedded_list_write_short_partial "p" + #define fss_embedded_list_write_short_prepend "P" + #define fss_embedded_list_write_short_single "s" + #define fss_embedded_list_write_short_trim "T" + + #define fss_embedded_list_write_long_file "file" + #define fss_embedded_list_write_long_content "content" + #define fss_embedded_list_write_long_double "double" + #define fss_embedded_list_write_long_ignore "ignore" + #define fss_embedded_list_write_long_object "object" + #define fss_embedded_list_write_long_partial "partial" + #define fss_embedded_list_write_long_prepend "prepend" + #define fss_embedded_list_write_long_single "single" + #define fss_embedded_list_write_long_trim "trim" + + enum { + fss_embedded_list_write_parameter_help, + fss_embedded_list_write_parameter_light, + fss_embedded_list_write_parameter_dark, + fss_embedded_list_write_parameter_no_color, + fss_embedded_list_write_parameter_verbosity_quiet, + fss_embedded_list_write_parameter_verbosity_normal, + fss_embedded_list_write_parameter_verbosity_verbose, + fss_embedded_list_write_parameter_verbosity_debug, + fss_embedded_list_write_parameter_version, + + fss_embedded_list_write_parameter_file, + fss_embedded_list_write_parameter_content, + fss_embedded_list_write_parameter_double, + fss_embedded_list_write_parameter_ignore, + fss_embedded_list_write_parameter_object, + fss_embedded_list_write_parameter_partial, + fss_embedded_list_write_parameter_prepend, + fss_embedded_list_write_parameter_single, + fss_embedded_list_write_parameter_trim, + }; + + #define fss_embedded_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_embedded_list_write_short_file, fss_embedded_list_write_long_file, 0, 1, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_embedded_list_write_short_content, fss_embedded_list_write_long_content, 0, 1, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_embedded_list_write_short_double, fss_embedded_list_write_long_double, 0, 0, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_embedded_list_write_short_ignore, fss_embedded_list_write_long_ignore, 0, 2, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_embedded_list_write_short_object, fss_embedded_list_write_long_object, 0, 1, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_embedded_list_write_short_partial, fss_embedded_list_write_long_partial, 0, 0, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_embedded_list_write_short_prepend, fss_embedded_list_write_long_prepend, 0, 1, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_embedded_list_write_short_single, fss_embedded_list_write_long_single, 0, 0, f_console_type_normal), \ + f_console_parameter_t_initialize(fss_embedded_list_write_short_trim, fss_embedded_list_write_long_trim, 0, 0, f_console_type_normal), \ + } + + #define fss_embedded_list_write_total_parameters 18 +#endif // _di_fss_embedded_list_write_defines_ + +#ifndef _di_fss_embedded_list_write_data_t_ + typedef struct { + f_console_parameter_t parameters[fss_embedded_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_embedded_list_write_data_t; + + #define fss_embedded_list_write_data_t_initialize \ + { \ + fss_embedded_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_embedded_list_write_data_t_ + +/** + * Print help. + * + * @param output + * The file to print to. + * @param context + * The color context settings. + * + * @return + * F_none on success. + */ +#ifndef _di_fss_embedded_list_write_print_help_ + extern f_return_status fss_embedded_list_write_print_help(const f_file_t output, const f_color_context_t context); +#endif // _di_fss_embedded_list_write_print_help_ + +/** + * Execute main program. + * + * Be sure to call fss_embedded_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_embedded_list_write_delete_data() + */ +#ifndef _di_fss_embedded_list_write_main_ + extern f_return_status fss_embedded_list_write_main(const f_console_arguments_t arguments, fss_embedded_list_write_data_t *data); +#endif // _di_fss_embedded_list_write_main_ + +/** + * Deallocate data. + * + * Be sure to call this after executing fss_embedded_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_embedded_list_write_main() + */ +#ifndef _di_fss_embedded_list_write_delete_data_ + extern f_return_status fss_embedded_list_write_delete_data(fss_embedded_list_write_data_t *data); +#endif // _di_fss_embedded_list_write_delete_data_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _fss_embedded_list_write_h diff --git a/level_3/fss_embedded_list_write/c/main.c b/level_3/fss_embedded_list_write/c/main.c new file mode 100644 index 0000000..7db7189 --- /dev/null +++ b/level_3/fss_embedded_list_write/c/main.c @@ -0,0 +1,16 @@ +#include "fss_embedded_list_write.h" + +int main(const unsigned long argc, const f_string_t *argv) { + const f_console_arguments_t arguments = { argc, argv }; + fss_embedded_list_write_data_t data = fss_embedded_list_write_data_t_initialize; + + if (f_pipe_input_exists()) { + data.process_pipe = F_true; + } + + if (F_status_is_error(fss_embedded_list_write_main(arguments, &data))) { + return 1; + } + + return 0; +} diff --git a/level_3/fss_embedded_list_write/c/private-fss_embedded_list_write.c b/level_3/fss_embedded_list_write/c/private-fss_embedded_list_write.c new file mode 100644 index 0000000..e3226df --- /dev/null +++ b/level_3/fss_embedded_list_write/c/private-fss_embedded_list_write.c @@ -0,0 +1,409 @@ +#include "fss_embedded_list_write.h" +#include "private-fss_embedded_list_write.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fss_embedded_list_write_error_parameter_same_times_print_ + void fss_embedded_list_write_error_parameter_same_times_print(const fss_embedded_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_embedded_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_embedded_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_embedded_list_write_long_partial); + fl_color_print(data.error.to.stream, data.context.set.error, "' parameter.%c", f_string_eol[0]); + } +#endif // _di_fss_embedded_list_write_error_parameter_same_times_print_ + +#ifndef _di_fss_embedded_list_write_error_parameter_unsupported_eol_print_ + void fss_embedded_list_write_error_parameter_unsupported_eol_print(const fss_embedded_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_embedded_list_write_error_parameter_unsupported_eol_print_ + +#ifndef _di_fss_embedded_list_write_error_parameter_value_missing_print_ + void fss_embedded_list_write_error_parameter_value_missing_print(const fss_embedded_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_embedded_list_write_error_parameter_value_missing_print_ + +#ifndef _di_fss_embedded_list_write_process_ + f_return_status fss_embedded_list_write_process(const fss_embedded_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, const f_string_ranges_t *ignore, f_string_dynamic_t *buffer) { + f_status_t status = F_none; + + f_string_range_t range = f_string_range_t_initialize; + + if (object) { + uint8_t complete = f_fss_complete_none; + + if (object->used) { + range.start = 0; + range.stop = object->used - 1; + } + else { + range.start = 1; + range.stop = 0; + } + + if (content) { + if (data.parameters[fss_embedded_list_write_parameter_trim].result == f_console_result_found) { + complete = f_fss_complete_full_trim; + } + else { + complete = f_fss_complete_full; + } + } + + status = fl_fss_embedded_list_object_write_string(*object, complete, &range, buffer); + + if (F_status_set_fine(status) == F_none_eol) { + fss_embedded_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_embedded_list_object_write_string", F_true); + return status; + } + } + + if (content && content->used) { + range.start = 0; + range.stop = content->used - 1; + + status = fl_fss_embedded_list_content_write_string(*content, object ? f_fss_complete_full : f_fss_complete_none, &data.prepend, ignore, &range, buffer); + + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "fl_fss_embedded_list_content_write_string", 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_embedded_list_write_process_ + +#ifndef _di_fss_embedded_list_write_process_pipe_ + f_return_status fss_embedded_list_write_process_pipe(const fss_embedded_list_write_data_t data, const f_file_t output, const f_fss_quote_t quote, f_string_dynamic_t *buffer, f_string_ranges_t *ignore) { + 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_range_t range_ignore = 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; + + range_ignore.start = 1; + range_ignore.stop = 0; + } + + if (object.used + block.used > object.size) { + status = fl_string_dynamic_increase_by(block.used, &object); + + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_increase_by", F_true); + break; + } + } + + for (; range.start <= range.stop; range.start++) { + + if (block.string[range.start] == fss_embedded_list_write_pipe_content_start) { + state = 0x2; + range.start++; + break; + } + + if (block.string[range.start] == fss_embedded_list_write_pipe_content_end) { + state = 0x3; + range.start++; + break; + } + + if (block.string[range.start] == fss_embedded_list_write_pipe_content_ignore) { + // this is not used by objects. + continue; + } + + 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_increase_by(total, &content); + + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_increase_by", F_true); + break; + } + } + + for (; range.start <= range.stop; range.start++) { + + if (block.string[range.start] == fss_embedded_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_embedded_list_write_pipe_content_end) { + state = 0x3; + range.start++; + break; + } + + if (block.string[range.start] == fss_embedded_list_write_pipe_content_ignore) { + if (ignore) { + if (range_ignore.start > range_ignore.stop) { + range_ignore.start = content.used; + range_ignore.stop = content.used; + } + else { + if (ignore->used + 1 > ignore->size) { + if (ignore->size + f_fss_default_allocation_step > f_array_length_t_size) { + if (ignore->size + 1 > f_array_length_t_size) { + fll_error_print(data.error, F_string_too_large, "fss_embedded_list_write_process_pipe", F_true); + + status = F_status_set_error(F_string_too_large); + break; + } + + f_macro_string_ranges_t_resize(status, (*ignore), ignore->size + 1); + } + else { + f_macro_string_ranges_t_resize(status, (*ignore), ignore->size + f_fss_default_allocation_step); + } + + if (F_status_is_error(status)) { + fll_error_print(data.error, F_string_too_large, "fss_embedded_list_write_process_pipe", F_true); + break; + } + } + + ignore->array[ignore->used].start = range_ignore.start; + ignore->array[ignore->used++].stop = content.used - 1; + + range_ignore.start = 1; + range_ignore.stop = 0; + } + } + + continue; + } + + content.string[content.used++] = block.string[range.start]; + } // for + + if (F_status_is_error(status)) break; + } + else { + state = 0x3; + } + } + + if (state == 0x3) { + status = fss_embedded_list_write_process(data, output, quote, &object, &content, ignore, 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_embedded_list_write_process(data, output, quote, &object, &content, ignore, 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_embedded_list_write_process_pipe_ + +#ifndef _di_fss_embedded_list_write_process_parameter_ignore_ + f_return_status fss_embedded_list_write_process_parameter_ignore(const f_console_arguments_t arguments, const fss_embedded_list_write_data_t data, const f_array_lengths_t contents, const f_array_length_t location, f_string_ranges_t *ignore) { + f_status_t status = F_none; + + f_array_length_t i = 0; + f_array_length_t l = 0; + f_array_length_t index = 0; + + f_string_range_t range = f_string_range_t_initialize; + + f_number_unsigned_t number = 0; + + range.start = 0; + + for (; i < data.parameters[fss_embedded_list_write_parameter_ignore].locations.used; i++) { + + l = data.parameters[fss_embedded_list_write_parameter_ignore].locations.array[i]; + + if (l < contents.array[location]) continue; + if (location + 1 < contents.used && l > contents.array[location + 1]) continue; + + if (ignore->used + 1 > ignore->size) { + if (ignore->size + f_fss_default_allocation_step > f_array_length_t_size) { + if (ignore->size + 1 > f_array_length_t_size) { + fll_error_print(data.error, F_string_too_large, "fss_embedded_list_write_process_parameter_ignore", F_true); + return F_status_set_error(F_string_too_large); + } + + f_macro_string_ranges_t_resize(status, (*ignore), ignore->size + 1); + } + else { + f_macro_string_ranges_t_resize(status, (*ignore), ignore->size + f_fss_default_allocation_step); + } + + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "fss_embedded_list_write_process_parameter_ignore", F_true); + return status; + } + } + + index = data.parameters[fss_embedded_list_write_parameter_ignore].values.array[i * 2]; + + range.start = 0; + range.stop = strnlen(arguments.argv[index], f_console_length_size) - 1; + + // allow and ignore the positive sign. + if (range.stop > 0 && arguments.argv[index][0] == '+') { + range.start = 1; + } + + status = fl_conversion_string_to_number_unsigned(arguments.argv[index], &number, range); + + if (F_status_is_error(status)) { + fll_error_parameter_integer_print(data.error, F_status_set_fine(status), "fl_conversion_string_to_number_unsigned", F_true, fss_embedded_list_write_long_ignore, arguments.argv[index]); + return status; + } + + ignore->array[ignore->used].start = number; + + index = data.parameters[fss_embedded_list_write_parameter_ignore].values.array[(i * 2) + 1]; + + range.start = 0; + range.stop = strnlen(arguments.argv[index], f_console_length_size) - 1; + + // allow and ignore the positive sign. + if (range.stop > 0 && arguments.argv[index][0] == '+') { + range.start = 1; + } + + status = fl_conversion_string_to_number_unsigned(arguments.argv[index], &number, range); + + if (F_status_is_error(status)) { + fll_error_parameter_integer_print(data.error, F_status_set_fine(status), "fl_conversion_string_to_number_unsigned", F_true, fss_embedded_list_write_long_ignore, arguments.argv[index]); + return status; + } + + ignore->array[ignore->used++].stop = number; + } // for + + return F_none; + } +#endif // _di_fss_embedded_list_write_process_parameter_ignore_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_3/fss_embedded_list_write/c/private-fss_embedded_list_write.h b/level_3/fss_embedded_list_write/c/private-fss_embedded_list_write.h new file mode 100644 index 0000000..4fbd049 --- /dev/null +++ b/level_3/fss_embedded_list_write/c/private-fss_embedded_list_write.h @@ -0,0 +1,129 @@ +/** + * FLL - Level 3 + * + * Project: FSS + * API Version: 0.5 + * Licenses: lgplv2.1 + */ +#ifndef _PRIVATE_fss_embedded_list_write_h +#define _PRIVATE_fss_embedded_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. + */ +#ifndef _di_fss_embedded_list_write_error_parameter_same_times_print_ + void fss_embedded_list_write_error_parameter_same_times_print(const fss_embedded_list_write_data_t data) f_gcc_attribute_visibility_internal; +#endif // _di_fss_embedded_list_write_error_parameter_same_times_print_ + +/** + * Print an message about a parameter EOL being unsupported. + * + * @param data + * The program data. + */ +#ifndef _di_fss_embedded_list_write_error_parameter_unsupported_eol_print_ + void fss_embedded_list_write_error_parameter_unsupported_eol_print(const fss_embedded_list_write_data_t data) f_gcc_attribute_visibility_internal; +#endif // _di_fss_embedded_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". + */ +#ifndef _di_fss_embedded_list_write_error_parameter_value_missing_print_ + void fss_embedded_list_write_error_parameter_value_missing_print(const fss_embedded_list_write_data_t data, const f_string_t symbol, const f_string_t parameter) f_gcc_attribute_visibility_internal; +#endif // _di_fss_embedded_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. + * Set pointer address to 0 to not use. + * @param content + * The content to escape and print. + * Set pointer address to 0 to not use. + * @param ignore + * An array of ranges within the Content to ignore. + * Set pointer address to 0 to not use. + * @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_embedded_list_write_process_ + extern f_return_status fss_embedded_list_write_process(const fss_embedded_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, const f_string_ranges_t *ignore, f_string_dynamic_t *buffer) f_gcc_attribute_visibility_internal; +#endif // _di_fss_embedded_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. + * @param ignore + * An array of ranges within the Content to ignore. + * Set pointer address to 0 to not use. + * + * @return + * F_none on success. + * F_failure (with error bit) for any othe failure. + */ +#ifndef _di_fss_embedded_list_write_process_pipe_ + extern f_return_status fss_embedded_list_write_process_pipe(const fss_embedded_list_write_data_t data, const f_file_t output, const f_fss_quote_t quote, f_string_dynamic_t *buffer, f_string_ranges_t *ignore) f_gcc_attribute_visibility_internal; +#endif // _di_fss_embedded_list_write_process_pipe_ + +/** + * Process the ignore parameter associated with a specific content parameter. + * + * @param arguments + * The parameters passed to the process. + * @param data + * The program data. + * @param contents + * The console parameter locations array for the content parameter. + * @param location + * The specific location within the contents locations array. + * @param ignore + * An array of ranges within the Content to ignore. + * + * @return + * F_none on success. + * F_failure (with error bit) for any othe failure. + */ +#ifndef _di_fss_embedded_list_write_process_parameter_ignore_ + extern f_return_status fss_embedded_list_write_process_parameter_ignore(const f_console_arguments_t arguments, const fss_embedded_list_write_data_t data, const f_array_lengths_t contents, const f_array_length_t location, f_string_ranges_t *ignore) f_gcc_attribute_visibility_internal; +#endif // _di_fss_embedded_list_write_process_parameter_ignore_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _PRIVATE_fss_embedded_list_write_h diff --git a/level_3/fss_embedded_list_write/data/build/defines b/level_3/fss_embedded_list_write/data/build/defines new file mode 100644 index 0000000..c665317 --- /dev/null +++ b/level_3/fss_embedded_list_write/data/build/defines @@ -0,0 +1,2 @@ +# fss-0000 + diff --git a/level_3/fss_embedded_list_write/data/build/dependencies b/level_3/fss_embedded_list_write/data/build/dependencies new file mode 100644 index 0000000..35c97b5 --- /dev/null +++ b/level_3/fss_embedded_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_embedded_list_write/data/build/settings b/level_3/fss_embedded_list_write/data/build/settings new file mode 100644 index 0000000..2ff7829 --- /dev/null +++ b/level_3/fss_embedded_list_write/data/build/settings @@ -0,0 +1,57 @@ +# fss-0001 + +project_name fss_embedded_list_write + +version_major 0 +version_minor 5 +version_micro 2 +version_target major + +environment + +process_pre +process_post + +modes individual level monolithic +modes_default monolithic + +build_compiler gcc +build_indexer ar +build_language c +build_libraries -lc +build_libraries-individual -lfll_error -lfll_execute -lfll_file -lfll_fss -lfll_program -lfl_color -lfl_console -lfl_conversion -lfl_directory -lfl_environment -lfl_fss -lfl_status -lfl_string -lf_console -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_utf +build_libraries-level -lfll_2 -lfll_1 -lfll_0 +build_libraries-monolithic -lfll +build_sources_library fss_embedded_list_write.c private-fss_embedded_list_write.c +build_sources_program main.c +build_sources_headers fss_embedded_list_write.h +build_sources_script +build_sources_setting +build_script yes +build_shared yes +build_static yes + +path_headers level_3 +path_headers_preserve no +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_list_write/c/fss_extended_list_write.h b/level_3/fss_extended_list_write/c/fss_extended_list_write.h index 214b4aa..791f225 100644 --- 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 @@ -5,7 +5,7 @@ * API Version: 0.5 * Licenses: lgplv2.1 * - * This program provides fss basic list write functionality. + * This program provides FSS-0003 Extended List write functionality. */ #ifndef _fss_extended_list_write_h @@ -51,7 +51,7 @@ extern "C" { #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" + #define fss_extended_list_write_name_long "FSS Extended List Write" #endif // _di_fss_extended_list_write_name_ #ifndef _di_fss_extended_list_write_defines_ -- 1.8.3.1