From: Kevin Day Date: Sat, 8 Jan 2022 23:40:49 +0000 (-0600) Subject: Feature: Add support for FSS-000E Payload specification. X-Git-Tag: 0.5.8~134 X-Git-Url: https://git.kevux.org/?a=commitdiff_plain;h=a6272eed8ece07e21461dbc1c9301d26c936c04e;p=fll Feature: Add support for FSS-000E Payload specification. Provide fss_payload_read and fss_payload_write to handle the special nature of this specification. This specification is primarily for network communication in which the payload can be a binary. --- diff --git a/build/level_2/settings b/build/level_2/settings index e596055..ddff97c 100644 --- a/build/level_2/settings +++ b/build/level_2/settings @@ -25,14 +25,14 @@ build_libraries-level -lfll_1 -lfll_0 build_libraries-level_threadless -lfll_1 -lfll_0 build_libraries_shared build_libraries_static -build_sources_library control_group.c error.c error-common.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_string.c iki.c private-iki.c path.c print.c program.c status_string.c +build_sources_library control_group.c error.c error-common.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_payload.c fss_status_string.c iki.c private-iki.c path.c print.c program.c status_string.c build_sources_library-level build_sources_library_shared build_sources_library_static build_sources_program build_sources_program_shared build_sources_program_static -build_sources_headers control_group.h 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_string.h iki.h path.h print.h program.h status_string.h +build_sources_headers control_group.h 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_payload.h fss_status_string.h iki.h path.h print.h program.h status_string.h build_sources_headers-level build_sources_headers_shared build_sources_headers_static diff --git a/build/monolithic/settings b/build/monolithic/settings index 7b8273d..9ceb952 100644 --- a/build/monolithic/settings +++ b/build/monolithic/settings @@ -25,14 +25,14 @@ build_libraries-monolithic build_libraries-monolithic_threadless build_libraries_shared build_libraries_static -build_sources_library level_0/account.c level_0/private-account.c level_0/capability.c level_0/color.c level_0/color-common.c level_0/console.c level_0/console-common.c level_0/control_group.c level_0/control_group-common.c level_0/conversion.c level_0/conversion-common.c level_0/private-conversion.c level_0/directory.c level_0/private-directory.c level_0/environment.c level_0/private-environment.c level_0/execute.c level_0/file.c level_0/file-common.c level_0/private-file.c level_0/fss.c level_0/private-fss.c level_0/fss-common.c level_0/fss_named.c level_0/fss_nest.c level_0/fss_set.c level_0/iki.c level_0/iki-common.c level_0/private-iki.c level_0/limit.c level_0/memory.c level_0/memory_structure.c level_0/private-memory.c level_0/path.c level_0/path-common.c level_0/private-path.c level_0/pipe.c level_0/print.c level_0/print_to.c level_0/print-common.c level_0/private-print.c level_0/private-print_to.c level_0/serialize.c level_0/serialize-common.c level_0/private-serialize.c level_0/signal.c level_0/socket.c level_0/status_string.c level_0/string.c level_0/string-common.c level_0/private-string.c level_0/string_dynamic.c level_0/string_map.c level_0/string_quantity.c level_0/string_range.c level_0/string_triple.c level_0/type_array.c level_0/private-type_array.c level_0/utf.c level_0/utf-common.c level_0/utf_dynamic.c level_0/utf_map.c level_0/utf_string.c level_0/utf_triple.c level_0/private-utf.c level_0/private-utf-is_unassigned.c level_0/private-utf_string.c level_1/console.c level_1/control_group.c level_1/conversion.c level_1/private-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/print-common.c level_1/private-print.c level_1/signal.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/control_group.c level_2/error.c level_2/error-common.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_string.c level_2/iki.c level_2/private-iki.c level_2/path.c level_2/print.c level_2/program.c level_2/status_string.c +build_sources_library level_0/account.c level_0/private-account.c level_0/capability.c level_0/color.c level_0/color-common.c level_0/console.c level_0/console-common.c level_0/control_group.c level_0/control_group-common.c level_0/conversion.c level_0/conversion-common.c level_0/private-conversion.c level_0/directory.c level_0/private-directory.c level_0/environment.c level_0/private-environment.c level_0/execute.c level_0/file.c level_0/file-common.c level_0/private-file.c level_0/fss.c level_0/private-fss.c level_0/fss-common.c level_0/fss_named.c level_0/fss_nest.c level_0/fss_set.c level_0/iki.c level_0/iki-common.c level_0/private-iki.c level_0/limit.c level_0/memory.c level_0/memory_structure.c level_0/private-memory.c level_0/path.c level_0/path-common.c level_0/private-path.c level_0/pipe.c level_0/print.c level_0/print_to.c level_0/print-common.c level_0/private-print.c level_0/private-print_to.c level_0/serialize.c level_0/serialize-common.c level_0/private-serialize.c level_0/signal.c level_0/socket.c level_0/status_string.c level_0/string.c level_0/string-common.c level_0/private-string.c level_0/string_dynamic.c level_0/string_map.c level_0/string_quantity.c level_0/string_range.c level_0/string_triple.c level_0/type_array.c level_0/private-type_array.c level_0/utf.c level_0/utf-common.c level_0/utf_dynamic.c level_0/utf_map.c level_0/utf_string.c level_0/utf_triple.c level_0/private-utf.c level_0/private-utf-is_unassigned.c level_0/private-utf_string.c level_1/console.c level_1/control_group.c level_1/conversion.c level_1/private-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/print-common.c level_1/private-print.c level_1/signal.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/control_group.c level_2/error.c level_2/error-common.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_payload.c level_2/fss_status_string.c level_2/iki.c level_2/private-iki.c level_2/path.c level_2/print.c level_2/program.c level_2/status_string.c build_sources_library-monolithic level_0/thread.c level_0/private-thread.c build_sources_library_shared build_sources_library_static build_sources_program build_sources_program_shared build_sources_program_static -build_sources_headers level_0/account.h level_0/account-common.h level_0/capability.h level_0/capability-common.h level_0/color.h level_0/color-common.h level_0/console.h level_0/console-common.h level_0/control_group.h level_0/control_group-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/execute.h level_0/execute-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/limit.h level_0/limit-common.h level_0/memory.h level_0/memory_structure.h level_0/memory-common.h level_0/path.h level_0/path-common.h level_0/pipe.h level_0/print.h level_0/print_to.h level_0/print-common.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_string.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/string_triple.h level_0/type.h level_0/type_array.h level_0/type_array-common.h level_0/utf.h level_0/utf-common.h level_0/utf_dynamic.h level_0/utf_map.h level_0/utf_string.h level_0/utf_triple.h level_1/console.h level_1/control_group.h level_1/conversion.h level_1/directory.h level_1/environment.h level_1/execute.h level_1/execute-common.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/iki.h level_1/print.h level_1/print-common.h level_1/signal.h level_1/signal-common.h level_1/string.h level_1/utf.h level_1/utf_file.h level_2/control_group.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_string.h level_2/iki.h level_2/path.h level_2/print.h level_2/program.h level_2/status_string.h +build_sources_headers level_0/account.h level_0/account-common.h level_0/capability.h level_0/capability-common.h level_0/color.h level_0/color-common.h level_0/console.h level_0/console-common.h level_0/control_group.h level_0/control_group-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/execute.h level_0/execute-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/limit.h level_0/limit-common.h level_0/memory.h level_0/memory_structure.h level_0/memory-common.h level_0/path.h level_0/path-common.h level_0/pipe.h level_0/print.h level_0/print_to.h level_0/print-common.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_string.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/string_triple.h level_0/type.h level_0/type_array.h level_0/type_array-common.h level_0/utf.h level_0/utf-common.h level_0/utf_dynamic.h level_0/utf_map.h level_0/utf_string.h level_0/utf_triple.h level_1/console.h level_1/control_group.h level_1/conversion.h level_1/directory.h level_1/environment.h level_1/execute.h level_1/execute-common.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/iki.h level_1/print.h level_1/print-common.h level_1/signal.h level_1/signal-common.h level_1/string.h level_1/utf.h level_1/utf_file.h level_2/control_group.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_payload.h level_2/fss_status_string.h level_2/iki.h level_2/path.h level_2/print.h level_2/program.h level_2/status_string.h build_sources_headers-monolithic level_0/thread.h level_0/thread-common.h build_sources_headers_shared build_sources_headers_static diff --git a/level_0/f_fss/c/fss-common.c b/level_0/f_fss/c/fss-common.c index be126fd..9953062 100644 --- a/level_0/f_fss/c/fss-common.c +++ b/level_0/f_fss/c/fss-common.c @@ -5,6 +5,11 @@ extern "C" { #endif +#ifndef _di_f_fss_strings_ + const f_string_t f_fss_string_header_s = F_fss_string_header_s; + const f_string_t f_fss_string_payload_s = F_fss_string_payload_s; +#endif // _di_f_fss_strings_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_0/f_fss/c/fss-common.h b/level_0/f_fss/c/fss-common.h index c25d0f1..7154875 100644 --- a/level_0/f_fss/c/fss-common.h +++ b/level_0/f_fss/c/fss-common.h @@ -98,23 +98,41 @@ extern "C" { #endif //_di_f_fss_delimiters_ /** + * Provide strings used by FSS. + * + * F_fss_string_*: + * - header: String representing the header Object name. + * - payload: String representing the payload Object name. + */ +#ifndef _di_f_fss_strings_ + #define F_fss_string_header_s "header" + #define F_fss_string_payload_s "payload" + + #define F_fss_string_header_s_length 6 + #define F_fss_string_payload_s_length 7 + + extern const f_string_t f_fss_string_header_s; + extern const f_string_t f_fss_string_payload_s; +#endif // _di_f_fss_strings_ + +/** * Codes for every known FSS standard. * * f_fss_*: - * - basic: FSS-0000: Basic. - * - extended: FSS-0001: Extended. - * - basic_list: FSS-0002: Basic List. - * - extended_list: FSS-0003: Extended List. - * - very_basic_list: FSS-0004: Very Basic List. - * - somewhat_basic_list: FSS-0005: Somewhat Basic List. - * - somewhat_extended_list: FSS-0006: Somewhat Extended List. - * - very_extended_list: FSS-0007: Very Extended List. - * - embedded_list: FSS-0008: Embedded List. - * - reverse_mapping: FSS-0009: Reverse Mapping. - * - extended_reverse_mapping: FSS-000A: Extended Reverse Mapping. - * - simple_list: FSS-000B: Simple List. - * - iki_text: FSS-000C: IKI Text. - * - basic_rule: FSS-000D: Basic Rule. + * - basic: FSS-0000: Basic. + * - extended: FSS-0001: Extended. + * - basic_list: FSS-0002: Basic List. + * - extended_list: FSS-0003: Extended List. + * - very_basic_list: FSS-0004: Very Basic List. + * - somewhat_basic_list: FSS-0005: Somewhat Basic List. + * - somewhat_extended_list: FSS-0006: Somewhat Extended List. + * - very_extended_list: FSS-0007: Very Extended List. + * - embedded_list: FSS-0008: Embedded List. + * - reverse_mapping: FSS-0009: Reverse Mapping. + * - extended_reverse_mapping: FSS-000A: Extended Reverse Mapping. + * - simple_list: FSS-000B: Simple List. + * - iki_text: FSS-000C: IKI Text. + * - basic_rule: FSS-000D: Basic Rule. */ #ifndef _di_f_fss_codes_ enum { @@ -144,13 +162,13 @@ extern "C" { * Only "next" and "end" are only meaningful for a Content and will be treated as "none" for an Object. * * f_fss_complete_*: - * - none: Disable completeness. - * - end: Complete as if this is the final piece of a set (such as FSS-0001, adding terminating EOL). - * - full: Complete and add terminating EOL, where applicable. - * - full_trim: Complete and add terminating EOL but remove any leading or trailing whitespace, where applicable. - * - next: Complete as if this is a piece of a set (such as FSS-0001, adding a separating space). - * - partial: Complete, but do not add terminating EOL, where applicable. - * - partial_trim: Complete, but do not add terminating EOL and remove any leading or trailing whitespace, where applicable. + * - none: Disable completeness. + * - end: Complete as if this is the final piece of a set (such as FSS-0001, adding terminating EOL). + * - full: Complete and add terminating EOL, where applicable. + * - full_trim: Complete and add terminating EOL but remove any leading or trailing whitespace, where applicable. + * - next: Complete as if this is a piece of a set (such as FSS-0001, adding a separating space). + * - partial: Complete, but do not add terminating EOL, where applicable. + * - partial_trim: Complete, but do not add terminating EOL and remove any leading or trailing whitespace, where applicable. */ #ifndef _di_f_fss_complete_ enum { @@ -207,6 +225,22 @@ enum { #endif // _di_f_fss_default_allocation_step_ /** + * Common FSS defaults. + * + * F_fss_default_*: + * - block_size_huge: The "huge" size in blocks to process for an FSS related task. + * - block_size_normal: The "normal" size in blocks to process for an FSS related task. + * - block_size_small: The "small" size in blocks to process for an FSS related task. + * - block_size_tiny: The "tiny" size in blocks to process for an FSS related task. + */ +#ifndef _di_f_fss_defaults_ + #define F_fss_default_block_size_huge_d 65536 + #define F_fss_default_block_size_normal_d 16384 + #define F_fss_default_block_size_small_d 4096 + #define F_fss_default_block_size_tiny_d 512 +#endif // _di_f_fss_defaults_ + +/** * This is a range that represents an object. */ #ifndef _di_fss_object_t_ diff --git a/level_1/fl_fss/c/fss_basic.c b/level_1/fl_fss/c/fss_basic.c index 8135cbb..798625e 100644 --- a/level_1/fl_fss/c/fss_basic.c +++ b/level_1/fl_fss/c/fss_basic.c @@ -53,7 +53,7 @@ extern "C" { return F_data_not_stop; } - macro_f_fss_content_t_increase(status, state.step_small, (*found)) + status = f_string_ranges_increase(state.step_small, found); if (F_status_is_error(status)) return status; found->array[found->used].start = range->start; diff --git a/level_1/fl_fss/c/fss_basic_list.c b/level_1/fl_fss/c/fss_basic_list.c index 466d9ff..7d55d06 100644 --- a/level_1/fl_fss/c/fss_basic_list.c +++ b/level_1/fl_fss/c/fss_basic_list.c @@ -290,7 +290,7 @@ extern "C" { private_macro_fl_fss_content_with_comments_return_on_overflow((buffer), (*range), (*found), (*delimits), delimits_used, (*comments), comments_used, F_none_eos, F_none_stop); - macro_f_fss_content_t_increase(status, state.step_small, (*found)) + status = f_string_ranges_increase(state.step_small, found); if (F_status_is_error(status)) return status; found->array[found->used].start = range->start; diff --git a/level_1/fl_fss/c/fss_extended_list.c b/level_1/fl_fss/c/fss_extended_list.c index 9b411c5..b70f03e 100644 --- a/level_1/fl_fss/c/fss_extended_list.c +++ b/level_1/fl_fss/c/fss_extended_list.c @@ -319,7 +319,7 @@ extern "C" { private_macro_fl_fss_content_with_comments_return_on_overflow((buffer), (*range), (*found), (*delimits), delimits_used, (*comments), comments_used, F_none_eos, F_none_stop); - macro_f_fss_content_t_increase(status, state.step_small, (*found)) + status = f_string_ranges_increase(state.step_small, found); if (F_status_is_error(status)) return status; found->array[found->used].start = range->start; diff --git a/level_2/fll_fss/c/fss_payload.c b/level_2/fll_fss/c/fss_payload.c new file mode 100644 index 0000000..ea7d6e1 --- /dev/null +++ b/level_2/fll_fss/c/fss_payload.c @@ -0,0 +1,243 @@ +#include "fss_basic_list.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fll_fss_payload_read_ + f_status_t fll_fss_payload_read(const f_string_static_t buffer, f_state_t state, f_string_range_t *range, f_fss_objects_t *objects, f_fss_contents_t *contents, f_fss_delimits_t *objects_delimits, f_fss_delimits_t *contents_delimits, f_fss_comments_t *comments) { + #ifndef _di_level_2_parameter_checking_ + if (!range) return F_status_set_error(F_parameter); + if (!objects) return F_status_set_error(F_parameter); + if (!contents) return F_status_set_error(F_parameter); + if (!objects_delimits) return F_status_set_error(F_parameter); + #endif // _di_level_2_parameter_checking_ + + f_status_t status = F_none; + f_status_t status2 = F_none; + f_array_length_t initial_used = objects->used; + + bool found_data = F_false; + + do { + if (objects->used == objects->size) { + macro_f_fss_objects_t_resize(status2, (*objects), objects->used + F_fss_default_allocation_step_d); + if (F_status_is_error(status)) return status; + + macro_f_fss_contents_t_resize(status2, (*contents), contents->used + F_fss_default_allocation_step_d); + if (F_status_is_error(status)) return status; + } + + do { + status = fl_fss_basic_list_object_read(buffer, state, range, &objects->array[objects->used], objects_delimits); + if (F_status_is_error(status)) return status; + + if (range->start >= range->stop || range->start >= buffer.used) { + if (status == F_fss_found_object || status == F_fss_found_object_content_not) { + if (fl_string_dynamic_partial_compare_string(F_fss_string_payload_s, buffer, F_fss_string_payload_s_length, objects->array[objects->used]) == F_equal_to) { + status = F_fss_found_object_content_not; + } + else { + + // Returning without a "payload" is an error. + status = F_status_set_error(F_fss_found_object_content_not); + } + + ++objects->used; + + status2 = f_string_ranges_increase(F_fss_default_allocation_step_small_d, &contents->array[contents->used]); + if (F_status_is_error(status2)) return status2; + + ++contents->used; + + return status; + } + + // Returning without a "payload" is an error. + if (found_data) { + if (range->start >= buffer.used) { + return F_status_set_error(F_none_eos); + } + + return F_status_set_error(F_none_stop); + } + + if (range->start >= buffer.used) { + return F_status_set_error(F_data_not_eos); + } + + return F_status_set_error(F_data_not_stop); + } + + if (status == F_fss_found_object) { + found_data = F_true; + + if (fl_string_dynamic_partial_compare_string(F_fss_string_payload_s, buffer, F_fss_string_payload_s_length, objects->array[objects->used]) == F_equal_to) { + status2 = f_string_ranges_increase(F_fss_default_allocation_step_small_d, &contents->array[contents->used]); + if (F_status_is_error(status)) return status; + + contents->array[contents->used].used = 1; + contents->array[contents->used].array[0].start = range->start; + + if (buffer.used > range->stop) { + contents->array[contents->used].array[0].stop = range->stop; + range->start = range->stop + 1; + status = F_none_stop; + } + else { + contents->array[contents->used].array[0].stop = buffer.used - 1; + range->start = buffer.used; + status = F_none_eos; + } + + ++objects->used; + ++contents->used; + + return status; + } + + status = fl_fss_basic_list_content_read(buffer, state, range, &contents->array[contents->used], contents_delimits ? contents_delimits : objects_delimits, comments); + if (F_status_is_error(status)) return status; + + break; + } + else if (status == F_fss_found_object_content_not) { + found_data = F_true; + + status2 = f_string_ranges_increase(F_fss_default_allocation_step_small_d, &contents->array[contents->used]); + if (F_status_is_error(status2)) return status2; + + if (fl_string_dynamic_partial_compare_string(F_fss_string_payload_s, buffer, F_fss_string_payload_s_length, objects->array[objects->used]) == F_equal_to) { + ++objects->used; + + status2 = f_string_ranges_increase(F_fss_default_allocation_step_small_d, &contents->array[contents->used]); + if (F_status_is_error(status2)) return status2; + + ++contents->used; + + return F_none; + } + + break; + } + } while (status == F_fss_found_object_not); + + if (status == F_none_eos || status == F_none_stop) { + ++contents->array[contents->used].used; + ++objects->used; + ++contents->used; + + // Returning without a "payload" is an error. + return F_status_set_error(status); + } + + 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 (objects->used > initial_used) { + + // Returning without a "payload" is an error. + if (status == F_data_not_eos) { + return F_status_set_error(F_none_eos); + } + + if (status == F_data_not_stop) { + return F_status_set_error(F_none_stop); + } + } + + return F_status_set_error(status); + } + + if (status != F_fss_found_object && status != F_fss_found_content && status != F_fss_found_content_not && status != F_fss_found_object_content_not) { + return status; + } + + if (range->start >= range->stop || range->start >= buffer.used) { + + // When content is found, the range->start is incremented, if content is found at range->stop, then range->start will be > range.stop. + if (status == F_fss_found_object || status == F_fss_found_content || status == F_fss_found_content_not || status == F_fss_found_object_content_not) { + ++objects->used; + ++contents->used; + } + + // Returning without a "payload" is an error. + if (range->start >= buffer.used) { + return F_status_set_error(F_none_eos); + } + + return F_status_set_error(F_none_stop); + } + + ++objects->used; + ++contents->used; + + } while (range->start < F_string_t_size_d); + + return F_status_is_error(F_number_overflow); + } +#endif // _di_fll_fss_payload_read_ + +#ifndef _di_fll_fss_payload_write_string_ + f_status_t fll_fss_payload_write_string(const f_string_static_t object, const f_string_static_t content, const bool trim, const f_string_static_t *content_prepend, f_state_t state, 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 = macro_f_string_range_t_initialize(object.used); + + status = fl_fss_basic_list_object_write(object, trim ? f_fss_complete_full_trim_e : f_fss_complete_full_e, state, &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 (fl_string_dynamic_compare_string(F_fss_string_payload_s, object, F_fss_string_payload_s_length) == F_equal_to) { + status = f_string_dynamic_increase_by(content.used, destination); + if (F_status_is_error(status)) return status; + + f_array_length_t i = 0; + + // Copy in blocks to allow for interruptability of potentially large data sets. + for (; i < content.used && i + F_fss_default_block_size_normal_d < content.used; i += F_fss_default_block_size_normal_d) { + + if (state.interrupt) { + status = state.interrupt((void *) &state, 0); + + if (F_status_set_fine(status) == F_interrupt) { + return F_status_set_error(F_interrupt); + } + } + + memcpy(destination->string + destination->used + i, content.string + i, F_fss_default_block_size_normal_d); + } // for + + if (i < content.used) { + memcpy(destination->string + destination->used + i, content.string + i, content.used - i); + } + + destination->used += content.used; + } + else { + if (content.used) { + range.start = 0; + range.stop = content.used - 1; + } + else { + range.start = 1; + range.stop = 0; + } + + status = fl_fss_basic_list_content_write(content, f_fss_complete_full_e, content_prepend, state, &range, destination); + } + } + + return status; + } +#endif // _di_fll_fss_payload_write_string_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_2/fll_fss/c/fss_payload.h b/level_2/fll_fss/c/fss_payload.h new file mode 100644 index 0000000..db24e0d --- /dev/null +++ b/level_2/fll_fss/c/fss_payload.h @@ -0,0 +1,156 @@ +/** + * FLL - Level 2 + * + * Project: FSS + * API Version: 0.5 + * Licenses: lgpl-2.1-or-later + * + * This is the fss-0002 implementation. + */ +#ifndef _FLL_fss_basic_list_h +#define _FLL_fss_basic_list_h + +// fll-0 includes +#include +#include +#include +#include +#include +#include + +// fll-1 includes +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Read a buffer expected to be in fss-000e format, getting all objects and their respective content. + * + * This processes only the outermost part and specially handles the payload. + * The inner data, such as the fss-0001 inside of the "header", should be directly processed via the appropriate function. + * + * The "payload" Object is required and if it is not file, this function returns with the error flag set. + * + * @param buffer + * The buffer to read from. + * @param state + * A state for handling interrupts during long running operations. + * There is no print_error() usage at this time (@todo this should be implemented and supported). + * There is no functions structure. + * There is no data structure passed to these functions (@todo the additional parameters could be moved to a custom structure). + * + * When interrupt() returns, only F_interrupt and F_interrupt_not are processed. + * Error bit designates an error but must be passed along with F_interrupt. + * All other statuses are ignored. + * @param range + * The range within the buffer that is currently being read. + * @param objects + * This will be populated with all valid objects found. + * @param contents + * This will be populated with all valid contents found. + * @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. + * 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_complete_not_utf (with error bit) is returned on failure to read/process a UTF-8 character due to the character being potentially incomplete. + * F_data_not_eos (with error bit) no data to write due start location being greater than or equal to buffer size, except that no "payload" is found. + * F_data_not_stop (with error bit) no data to write due start location being greater than stop location, except that no "payload" is found. + * F_interrupt (with error bit) if stopping due to an interrupt. + * F_memory_not (with error bit) on out of memory. + * F_none (with error bit) on success, except that no "payload" is found. + * F_none_eos (with error bit) on success after reaching the end of the buffer, except that no "payload" is found. + * F_none_stop (with error bit) on success after reaching stopping point, except that no "payload" is found. + * F_number_overflow (with error bit) if the maximimum buffer size is reached. + * 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_basic_list_content_read(). + * Errors (with error bit) from: fl_fss_basic_list_object_read(). + * + * @see fl_fss_basic_list_content_read() + * @see fl_fss_basic_list_object_read() + */ +#ifndef _di_fll_fss_payload_read_ + extern f_status_t fll_fss_payload_read(const f_string_static_t buffer, f_state_t state, f_string_range_t *range, f_fss_objects_t *objects, f_fss_contents_t *contents, f_fss_delimits_t *objects_delimits, f_fss_delimits_t *contents_delimits, f_fss_comments_t *comments); +#endif // _di_fll_fss_payload_read_ + +/** + * Write a single object string and content string to a buffer, using fss-0002 format. + * + * This processes only the outermost part and specially handles the payload. + * The inner data, such as the fss-0001 inside of the "header", should be directly processed via the appropriate function. + * + * If the Object is "payload", then the Content is written directly without prcessing or escaping. + * + * @param object + * A string representing the object. + * @param content + * A string representing the content. + * @param trim + * If TRUE, the Object is passed f_fss_complete_full_trim_e. + * If FALSE, the Object is passed f_fss_complete_full_e. + * The Content is always passed f_fss_complete_full_e. + * @param content_prepend + * A string to prepend at the start of each line in content, such as spaces. + * This will not be prepended for the Object "payload". + * Set the pointer address to 0 to disable. + * @param state + * A state for handling interrupts during long running operations. + * There is no print_error() usage at this time (@todo this should be implemented and supported). + * There is no functions structure. + * There is no data structure passed to these functions (@todo the additional parameters could be moved to a custom structure). + * + * When interrupt() returns, only F_interrupt and F_interrupt_not are processed. + * Error bit designates an error but must be passed along with F_interrupt. + * All other statuses are ignored. + * @param destination + * The buffer to write 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_complete_not_utf (with error bit) is returned on failure to read/process a UTF-8 character due to the character being potentially incomplete. + * F_interrupt (with error bit) if stopping due to an interrupt. + * F_memory_not (with error bit) on out of memory. + * 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_string_dynamic_increase_by(). + * Errors (with error bit) from: fl_fss_basic_list_content_write(). + * Errors (with error bit) from: fl_fss_basic_list_object_write(). + * + * @see f_string_dynamic_increase_by() + * @see fl_fss_basic_list_content_write() + * @see fl_fss_basic_list_object_write() + */ +#ifndef _di_fll_fss_payload_write_string_ + extern f_status_t fll_fss_payload_write_string(const f_string_static_t object, const f_string_static_t content, const bool trim, const f_string_static_t *content_prepend, f_state_t state, f_string_dynamic_t *destination); +#endif // _di_fll_fss_payload_write_string_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FLL_fss_basic_list_h diff --git a/level_2/fll_fss/data/build/settings b/level_2/fll_fss/data/build/settings index 20e3a78..3cc7a93 100644 --- a/level_2/fll_fss/data/build/settings +++ b/level_2/fll_fss/data/build/settings @@ -24,13 +24,13 @@ build_libraries -lc build_libraries-individual -lfl_conversion -lfl_fss -lfl_string -lf_conversion -lf_file -lf_fss -lf_memory -lf_status_string -lf_string -lf_type_array -lf_utf build_libraries_shared build_libraries_static -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 +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_payload.c build_sources_library_shared build_sources_library_static build_sources_program build_sources_program_shared build_sources_program_static -build_sources_headers fss.h fss_basic.h fss_basic_list.h fss_embedded_list.h fss_extended.h fss_extended_list.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_payload.h build_sources_headers_shared build_sources_headers_static build_sources_script diff --git a/level_3/fss_payload_read/c/fss_payload_read.c b/level_3/fss_payload_read/c/fss_payload_read.c new file mode 100644 index 0000000..fe45a11 --- /dev/null +++ b/level_3/fss_payload_read/c/fss_payload_read.c @@ -0,0 +1,701 @@ +#include "fss_payload_read.h" +#include "private-common.h" +#include "private-fss_payload_read.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fss_payload_read_print_help_ + f_status_t fss_payload_read_print_help(const f_file_t file, const f_color_context_t context) { + + flockfile(file.stream); + + fll_program_print_help_header(file, context, fss_payload_program_name_long_s, fss_payload_program_version_s); + + fll_program_print_help_option(file, context, f_console_standard_short_help_s, f_console_standard_long_help_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Print this help message."); + fll_program_print_help_option(file, context, f_console_standard_short_dark_s, f_console_standard_long_dark_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Output using colors that show up better on dark backgrounds."); + fll_program_print_help_option(file, context, f_console_standard_short_light_s, f_console_standard_long_light_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Output using colors that show up better on light backgrounds."); + fll_program_print_help_option(file, context, f_console_standard_short_no_color_s, f_console_standard_long_no_color_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, "Do not file in color."); + fll_program_print_help_option(file, context, f_console_standard_short_quiet_s, f_console_standard_long_quiet_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Decrease verbosity, silencing most output."); + fll_program_print_help_option(file, context, f_console_standard_short_normal_s, f_console_standard_long_normal_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Set verbosity to normal file."); + fll_program_print_help_option(file, context, f_console_standard_short_verbose_s, f_console_standard_long_verbose_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Increase verbosity beyond normal output."); + fll_program_print_help_option(file, context, f_console_standard_short_debug_s, f_console_standard_long_debug_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Enable debugging, significantly increasing verbosity beyond normal output."); + fll_program_print_help_option(file, context, f_console_standard_short_version_s, f_console_standard_long_version_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Print only the version number."); + + f_print_character(f_string_eol_s[0], file.stream); + + fll_program_print_help_option(file, context, fss_payload_read_short_at_s, fss_payload_read_long_at_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Select Object at this numeric index."); + fll_program_print_help_option(file, context, fss_payload_read_short_content_s, fss_payload_read_long_content_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Print the Content (default)."); + fll_program_print_help_option(file, context, fss_payload_read_short_columns_s, fss_payload_read_long_columns_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Print the total number of columns."); + fll_program_print_help_option(file, context, fss_payload_read_short_delimit_s, fss_payload_read_long_delimit_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Designate how to handle applying delimits."); + fll_program_print_help_option(file, context, fss_payload_read_short_depth_s, fss_payload_read_long_depth_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Select Object at this numeric depth."); + fll_program_print_help_option(file, context, fss_payload_read_short_empty_s, fss_payload_read_long_empty_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Include empty Content when processing."); + fll_program_print_help_option(file, context, fss_payload_read_short_line_s, fss_payload_read_long_line_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Print only the Content at the given line."); + fll_program_print_help_option(file, context, fss_payload_read_short_name_s, fss_payload_read_long_name_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Select Object with this name."); + fll_program_print_help_option(file, context, fss_payload_read_short_object_s, fss_payload_read_long_object_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Print the Object."); + fll_program_print_help_option(file, context, fss_payload_read_short_pipe_s, fss_payload_read_long_pipe_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Print using the special pipe format."); + fll_program_print_help_option(file, context, fss_payload_read_short_raw_s, fss_payload_read_long_raw_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Print with the original quotes and escapes."); + fll_program_print_help_option(file, context, fss_payload_read_short_select_s, fss_payload_read_long_select_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Select sub-Content at this index."); + fll_program_print_help_option(file, context, fss_payload_read_short_total_s, fss_payload_read_long_total_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Print the total number of lines."); + fll_program_print_help_option(file, context, fss_payload_read_short_trim_s, fss_payload_read_long_trim_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Trim Object names on select or print."); + + fll_program_print_help_usage(file, context, fss_payload_program_name_s, "filename(s)"); + + fl_print_format(" %[Notes:%]%c", file.stream, context.set.important, context.set.important, f_string_eol_s[0]); + + fl_print_format(" This program will print the Content associated with the given Object and Content main based on the FSS-000E Payload standard.%c%c", file.stream, f_string_eol_s[0], f_string_eol_s[0]); + + fl_print_format(" All numeric positions (indexes) start at 0 instead of 1.%c", file.stream, f_string_eol_s[0]); + fl_print_format(" For example, a file of 17 lines would range from 0 to 16.%c%c", file.stream, f_string_eol_s[0], f_string_eol_s[0]); + + fl_print_format(" When using the %[%s%s%] option, an order of operations is enforced on the parameters.%c", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_depth_s, context.set.notable, f_string_eol_s[0]); + + fl_print_format(" When this order of operations is in effect, parameters to the right of a depth parameter are influenced by that depth parameter:%c", file.stream, f_string_eol_s[0]); + + fl_print_format(" %[%s%s%]: An Object index at the specified depth.%c", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_at_s, context.set.notable, f_string_eol_s[0]); + fl_print_format(" %[%s%s%]: A new depth within the specified depth, indexed from the root.%c", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_depth_s, context.set.notable, f_string_eol_s[0]); + fl_print_format(" %[%s%s%]: An Object name at the specified depth.%c%c", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_name_s, context.set.notable, f_string_eol_s[0], f_string_eol_s[0]); + + fl_print_format(" The parameter %[%s%s%] must be in numeric order, but values in between may be skipped.%c", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_depth_s, context.set.notable, f_string_eol_s[0]); + fl_print_format(" ('-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", file.stream, f_string_eol_s[0]); + fl_print_format(" ('-d 2 -a 1 -d 0 -a 2' would be invalid because depth 2 is before depth 1.)%c%c", file.stream, f_string_eol_s[0], f_string_eol_s[0]); + + fl_print_format(" The parameter %[%s%s%] selects a Content column.%c%c", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_select_s, context.set.notable, f_string_eol_s[0], f_string_eol_s[0]); + + fl_print_format(" Specify both %[%s%s%]", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_object_s, context.set.notable); + fl_print_format(" and the %[%s%s%] parameters to get the total objects.%c%c", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_total_s, context.set.notable, f_string_eol_s[0], f_string_eol_s[0]); + + fl_print_format(" When both %[%s%s%]", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_at_s, context.set.notable); + fl_print_format(" and %[%s%s%] parameters are specified (at the same depth),", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_name_s, context.set.notable); + fl_print_format(" the %[%s%s%] parameter value will be treated as a position relative to the specified", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_at_s, context.set.notable); + fl_print_format(" %[%s%s%] parameter value.%c%c", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_name_s, context.set.notable, f_string_eol_s[0], f_string_eol_s[0]); + + fl_print_format(" This program may support parameters, such as %[%s%s%]", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_depth_s, context.set.notable); + fl_print_format(" or %[%s%s%], even if not supported by the standard.%c", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_select_s, context.set.notable, f_string_eol_s[0]); + fl_print_format(" This is done to help ensure consistency for scripting.%c%c", file.stream, f_string_eol_s[0], f_string_eol_s[0]); + + fl_print_format(" For parameters like %[%s%s%],", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_depth_s, context.set.notable); + fl_print_format(" if the standard doesn't support nested Content, then only a depth of 0 would be valid.%c", file.stream, f_string_eol_s[0]); + + fl_print_format(" For parameters like %[%s%s%],", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_select_s, context.set.notable); + fl_print_format(" if the standard doesn't support multiple Content groups, then only a select of 0 would be valid.%c%c", file.stream, f_string_eol_s[0], f_string_eol_s[0]); + + fl_print_format(" The parameter %[%s%s%]", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_trim_s, context.set.notable); + fl_print_format(" will remove leading and trailing whitespaces when selecting objects or when printing objects.%c%c", file.stream, f_string_eol_s[0], f_string_eol_s[0]); + + fl_print_format(" When specifying both the %[%s%s%]", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_object_s, context.set.notable); + fl_print_format(" parameter and the %[%s%s%] parameter, the entire Object and Content are printed, including the formatting.%c", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_content_s, context.set.notable, f_string_eol_s[0]); + fl_print_format(" Both the Object and Content printed are already escaped.%c", file.stream, f_string_eol_s[0]); + fl_print_format(" Both the Object and Content are separated by an EOL.%c%c", file.stream, f_string_eol_s[0], f_string_eol_s[0]); + + fl_print_format(" The parameter %[%s%s%] accepts the following:%c", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_delimit_s, context.set.notable, f_string_eol_s[0]); + fl_print_format(" - %[%s%]: Do not apply delimits.%c", file.stream, context.set.notable, fss_payload_read_delimit_mode_name_none_s, context.set.notable, f_string_eol_s[0]); + fl_print_format(" - %[%s%]: (default) Apply all delimits.%c", file.stream, context.set.notable, fss_payload_read_delimit_mode_name_all_s, context.set.notable, f_string_eol_s[0]); + fl_print_format(" - %[%s%]: Apply delimits for Objects.%c", file.stream, context.set.notable, fss_payload_read_delimit_mode_name_object_s, context.set.notable, f_string_eol_s[0]); + fl_print_format(" - A number, 0 or greater: apply delimits for Content at the specified depth.%c", file.stream, f_string_eol_s[0]); + fl_print_format(" - A number, 0 or greater, followed by a %[%s%]: (such as '1+') apply delimits for Content at the specified depth and any greater depth (numerically).%c", file.stream, context.set.notable, fss_payload_read_delimit_mode_name_greater_s, context.set.notable, f_string_eol_s[0], f_string_eol_s[0]); + fl_print_format(" - A number, 0 or lesser, followed by a %[%s%]: (such as '1-') apply delimits for Content at the specified depth and any lesser depth (numerically).%c%c", file.stream, context.set.notable, fss_payload_read_delimit_mode_name_lesser_s, context.set.notable, f_string_eol_s[0], f_string_eol_s[0]); + + fl_print_format(" The %[%s%s%] parameter may be specified multiple times to customize the delimit behavior.%c", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_delimit_s, context.set.notable, f_string_eol_s[0]); + + fl_print_format(" The %[%s%s%]", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_delimit_s, context.set.notable); + fl_print_format(" values %[%s%]", file.stream, context.set.notable, fss_payload_read_delimit_mode_name_none_s, context.set.notable); + fl_print_format(" and %[%s%],", file.stream, context.set.notable, fss_payload_read_delimit_mode_name_all_s, context.set.notable); + fl_print_format(" overrule all other delimit values.%c%c", file.stream, f_string_eol_s[0], f_string_eol_s[0]); + + fl_print_format(" The parameters %[%s%s%]", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_columns_s, context.set.notable); + fl_print_format(" and %[%s%s%]", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_select_s, context.set.notable); + fl_print_format(" refer to a Content column.%c", file.stream, f_string_eol_s[0]); + fl_print_format(" The word \"column\" is being loosely defined to refer to a specific Content.%c", file.stream, f_string_eol_s[0]); + fl_print_format(" This is not to be confused with a depth.%c%c", file.stream, f_string_eol_s[0], f_string_eol_s[0]); + + fl_print_format(" As an exceptional case, a %[%s%s%] of", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_depth_s, context.set.notable); + fl_print_format(" %[1%] applies only to the explicit Object of", file.stream, context.set.notable, context.set.notable); + fl_print_format(" '%[%s%]'.%c", file.stream, context.set.notable, f_fss_string_header_s, context.set.notable, f_string_eol_s[0]); + fl_print_format(" Content at this depth is processed as FSS-0001 Extended.%c%c", file.stream, f_string_eol_s[0], f_string_eol_s[0]); + + fl_print_format(" The Content of the explicit Object of", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_depth_s, context.set.notable); + fl_print_format(" '%[%s%]'", file.stream, context.set.notable, f_fss_string_payload_s, context.set.notable, f_string_eol_s[0]); + fl_print_format(" will not contain any Content close pipe control codes when using", file.stream); + fl_print_format(" %[%s%s%].%c%c", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_read_long_pipe_s, context.set.notable, f_string_eol_s[0], f_string_eol_s[0]); + + funlockfile(file.stream); + + return F_none; + } +#endif // _di_fss_payload_read_print_help_ + +#ifndef _di_fss_payload_read_main_ + f_status_t fss_payload_read_main(fss_payload_read_main_t * const main, const f_console_arguments_t *arguments) { + + f_status_t status = F_none; + + { + const f_console_parameters_t parameters = macro_f_console_parameters_t_initialize(main->parameters, fss_payload_total_parameters_d); + + { + f_console_parameter_id_t ids[3] = { fss_payload_read_parameter_no_color_e, fss_payload_read_parameter_light_e, fss_payload_read_parameter_dark_e }; + const f_console_parameter_ids_t choices = { ids, 3 }; + + status = fll_program_parameter_process(*arguments, parameters, choices, F_true, &main->remaining, &main->context); + + main->output.set = &main->context.set; + main->error.set = &main->context.set; + main->warning.set = &main->context.set; + + if (main->context.set.error.before) { + main->output.context = f_color_set_empty_s; + main->output.notable = main->context.set.notable; + + main->error.context = main->context.set.error; + main->error.notable = main->context.set.notable; + + main->warning.context = main->context.set.warning; + main->warning.notable = main->context.set.notable; + } + else { + f_color_set_t *sets[] = { &main->output.context, &main->output.notable, &main->error.context, &main->error.notable, &main->warning.context, &main->warning.notable, 0 }; + + fll_program_parameter_process_empty(&main->context, sets); + } + + if (F_status_is_error(status)) { + fss_payload_read_main_delete(main); + + return F_status_set_error(status); + } + } + + // Identify priority of verbosity related parameters. + { + f_console_parameter_id_t ids[4] = { fss_payload_read_parameter_verbosity_quiet_e, fss_payload_read_parameter_verbosity_normal_e, fss_payload_read_parameter_verbosity_verbose_e, fss_payload_read_parameter_verbosity_debug_e }; + f_console_parameter_id_t choice = 0; + const f_console_parameter_ids_t choices = macro_f_console_parameter_ids_t_initialize(ids, 4); + + status = f_console_parameter_prioritize_right(parameters, choices, &choice); + + if (F_status_is_error(status)) { + fss_payload_read_main_delete(main); + + return status; + } + + if (choice == fss_payload_read_parameter_verbosity_quiet_e) { + main->output.verbosity = f_console_verbosity_quiet_e; + main->error.verbosity = f_console_verbosity_quiet_e; + main->warning.verbosity = f_console_verbosity_quiet_e; + } + else if (choice == fss_payload_read_parameter_verbosity_normal_e) { + main->output.verbosity = f_console_verbosity_normal_e; + main->error.verbosity = f_console_verbosity_normal_e; + main->warning.verbosity = f_console_verbosity_normal_e; + } + else if (choice == fss_payload_read_parameter_verbosity_verbose_e) { + main->output.verbosity = f_console_verbosity_verbose_e; + main->error.verbosity = f_console_verbosity_verbose_e; + main->warning.verbosity = f_console_verbosity_verbose_e; + } + else if (choice == fss_payload_read_parameter_verbosity_debug_e) { + main->output.verbosity = f_console_verbosity_debug_e; + main->error.verbosity = f_console_verbosity_debug_e; + main->warning.verbosity = f_console_verbosity_debug_e; + } + } + + status = F_none; + } + + if (main->parameters[fss_payload_read_parameter_help_e].result == f_console_result_found_e) { + fss_payload_read_print_help(main->output.to, main->context); + + fss_payload_read_main_delete(main); + return status; + } + + if (main->parameters[fss_payload_read_parameter_version_e].result == f_console_result_found_e) { + fll_program_print_version(main->output.to, fss_payload_program_version_s); + + fss_payload_read_main_delete(main); + return status; + } + + // Provide a range designating where within the buffer a particular file exists, using a statically allocated array. + fss_payload_read_file_t files_array[main->remaining.used + 1]; + fss_payload_read_data_t data = fss_payload_read_data_t_initialize; + + data.files.array = files_array; + data.files.used = 1; + data.files.size = main->remaining.used + 1; + data.files.array[0].name = "(pipe)"; + data.files.array[0].range.start = 1; + data.files.array[0].range.stop = 0; + + if (main->remaining.used || main->process_pipe) { + { + const f_array_length_t parameter_code[] = { + fss_payload_read_parameter_at_e, + fss_payload_read_parameter_depth_e, + fss_payload_read_parameter_line_e, + fss_payload_read_parameter_select_e, + fss_payload_read_parameter_name_e, + fss_payload_read_parameter_delimit_e, + }; + + const f_string_t parameter_name[] = { + fss_payload_read_long_at_s, + fss_payload_read_long_depth_s, + fss_payload_read_long_line_s, + fss_payload_read_long_select_s, + fss_payload_read_long_name_s, + fss_payload_read_long_delimit_s, + }; + + const f_string_t message_positive_number = "positive number"; + const f_string_t message_string = "string"; + const f_string_t message_value = "value"; + + const f_string_t parameter_message[] = { + message_positive_number, + message_positive_number, + message_positive_number, + message_positive_number, + message_string, + message_value, + }; + + for (f_array_length_t i = 0; i < 6; ++i) { + + if (main->parameters[parameter_code[i]].result == f_console_result_found_e) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sThe parameter '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, parameter_name[i], main->error.notable); + fl_print_format("%[' requires a %s.%]%c", main->error.to.stream, main->error.context, parameter_message[i], main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + + status = F_status_set_error(F_parameter); + break; + } + } // for + } + + if (F_status_is_error_not(status) && main->parameters[fss_payload_read_parameter_columns_e].result == f_console_result_found_e) { + const f_array_length_t parameter_code[] = { + fss_payload_read_parameter_depth_e, + fss_payload_read_parameter_line_e, + fss_payload_read_parameter_pipe_e, + fss_payload_read_parameter_select_e, + fss_payload_read_parameter_total_e, + }; + + const f_string_t parameter_name[] = { + fss_payload_read_long_depth_s, + fss_payload_read_long_line_s, + fss_payload_read_long_pipe_s, + fss_payload_read_long_select_s, + fss_payload_read_long_total_s, + }; + + const uint8_t parameter_match[] = { + f_console_result_additional_e, + f_console_result_additional_e, + f_console_result_found_e, + f_console_result_additional_e, + f_console_result_found_e, + }; + + for (f_array_length_t i = 0; i < 5; ++i) { + + if (main->parameters[parameter_code[i]].result == parameter_match[i]) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sCannot specify the '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_read_long_columns_s, main->error.notable); + fl_print_format("%[' parameter with the '%]", main->error.to.stream, main->error.context, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, parameter_name[i], main->error.notable); + fl_print_format("%[' parameter.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + + status = F_status_set_error(F_parameter); + break; + } + } // for + } + + if (F_status_is_error_not(status) && main->parameters[fss_payload_read_parameter_pipe_e].result == f_console_result_found_e) { + if (main->parameters[fss_payload_read_parameter_total_e].result == f_console_result_found_e) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sCannot specify the '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_read_long_pipe_s, main->error.notable); + fl_print_format("%[' parameter with the '%]", main->error.to.stream, main->error.context, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_read_long_total_s, main->error.notable); + fl_print_format("%[' parameter.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + + status = F_status_set_error(F_parameter); + } + else if (main->parameters[fss_payload_read_parameter_line_e].result == f_console_result_additional_e) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sCannot specify the '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_read_long_pipe_s, main->error.notable); + fl_print_format("%[' parameter with the '%]", main->error.to.stream, main->error.context, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_read_long_line_s, main->error.notable); + fl_print_format("%[' parameter.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + + status = F_status_set_error(F_parameter); + } + } + + if (F_status_is_error_not(status) && main->parameters[fss_payload_read_parameter_delimit_e].result == f_console_result_additional_e) { + f_array_length_t location = 0; + f_array_length_t length = 0; + uint16_t signal_check = 0; + + // Set the value to 0 to allow for detecting mode based on what is provided. + data.delimit_mode = 0; + + for (f_array_length_t i = 0; i < main->parameters[fss_payload_read_parameter_delimit_e].values.used; ++i) { + + if (!((++signal_check) % fss_payload_read_signal_check_d)) { + if (fss_payload_read_signal_received(main)) { + status = F_status_set_error(F_interrupt); + break; + } + + signal_check = 0; + } + + location = main->parameters[fss_payload_read_parameter_delimit_e].values.array[i]; + length = strnlen(arguments->argv[location], f_console_parameter_size); + + if (!length) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sThe value for the parameter '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_read_long_delimit_s, main->error.notable); + fl_print_format("%[' must not be empty.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + + status = F_status_set_error(F_parameter); + break; + } + else if (fl_string_compare(arguments->argv[location], fss_payload_read_delimit_mode_name_none_s, length, fss_payload_read_delimit_mode_name_none_s_length) == F_equal_to) { + data.delimit_mode = fss_payload_read_delimit_mode_none_e; + } + else if (fl_string_compare(arguments->argv[location], fss_payload_read_delimit_mode_name_all_s, length, fss_payload_read_delimit_mode_name_all_s_length) == F_equal_to) { + data.delimit_mode = fss_payload_read_delimit_mode_all_e; + } + else if (fl_string_compare(arguments->argv[location], fss_payload_read_delimit_mode_name_object_s, length, fss_payload_read_delimit_mode_name_object_s_length) == F_equal_to) { + switch (data.delimit_mode) { + case 0: + data.delimit_mode = fss_payload_read_delimit_mode_object_e; + break; + + case fss_payload_read_delimit_mode_none_e: + case fss_payload_read_delimit_mode_all_e: + case fss_payload_read_delimit_mode_content_greater_object_e: + case fss_payload_read_delimit_mode_content_lesser_object_e: + case fss_payload_read_delimit_mode_object_e: + break; + + case fss_payload_read_delimit_mode_content_e: + data.delimit_mode = fss_payload_read_delimit_mode_content_object_e; + break; + + case fss_payload_read_delimit_mode_content_greater_e: + data.delimit_mode = fss_payload_read_delimit_mode_content_greater_object_e; + break; + + case fss_payload_read_delimit_mode_content_lesser_e: + data.delimit_mode = fss_payload_read_delimit_mode_content_lesser_object_e; + break; + + default: + break; + } + } + else { + if (!data.delimit_mode) { + data.delimit_mode = fss_payload_read_delimit_mode_content_e; + } + else if (data.delimit_mode == fss_payload_read_delimit_mode_object_e) { + data.delimit_mode = fss_payload_read_delimit_mode_content_object_e; + } + + if (arguments->argv[location][length - 1] == fss_payload_read_delimit_mode_name_greater_s[0]) { + if (!(data.delimit_mode == fss_payload_read_delimit_mode_none_e || data.delimit_mode == fss_payload_read_delimit_mode_all_e)) { + if (data.delimit_mode == fss_payload_read_delimit_mode_content_object_e) { + data.delimit_mode = fss_payload_read_delimit_mode_content_greater_object_e; + } + else { + data.delimit_mode = fss_payload_read_delimit_mode_content_greater_e; + } + } + + // Shorten the length to better convert the remainder to a number. + --length; + } + else if (arguments->argv[location][length - 1] == fss_payload_read_delimit_mode_name_lesser_s[0]) { + if (!(data.delimit_mode == fss_payload_read_delimit_mode_none_e || data.delimit_mode == fss_payload_read_delimit_mode_all_e)) { + if (data.delimit_mode == fss_payload_read_delimit_mode_content_object_e) { + data.delimit_mode = fss_payload_read_delimit_mode_content_lesser_object_e; + } + else { + data.delimit_mode = fss_payload_read_delimit_mode_content_lesser_e; + } + } + + // Shorten the length to better convert the remainder to a number. + --length; + } + + f_string_range_t range = macro_f_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], range, &data.delimit_depth); + + if (F_status_is_error(status)) { + fll_error_parameter_integer_print(main->error, F_status_set_fine(status), "fl_conversion_string_to_number_unsigned", F_true, fss_payload_read_long_delimit_s, arguments->argv[location]); + + break; + } + + // There can be nothing smaller than 0, so replace '0-' logic with just '0' logic. + if (data.delimit_mode == fss_payload_read_delimit_mode_content_lesser_e || data.delimit_mode == fss_payload_read_delimit_mode_content_lesser_object_e) { + if (!data.delimit_depth) { + if (data.delimit_mode == fss_payload_read_delimit_mode_content_lesser_e) { + data.delimit_mode = fss_payload_read_delimit_mode_content_e; + } + else { + data.delimit_mode = fss_payload_read_delimit_mode_content_object_e; + } + } + } + } + } // for + + // Guarantee the default value is "all". + if (F_status_is_error_not(status) && !data.delimit_mode) { + data.delimit_mode = fss_payload_read_delimit_mode_all_e; + } + } + + if (F_status_is_error_not(status)) { + status = fss_payload_read_depth_process(main, arguments, &data); + } + + // This standard only partially supports nesting, so any depth greater than 1 can be predicted without processing the file. + if (F_status_is_error_not(status)) { + for (f_array_length_t i = 0; i < data.depths.used; ++i) { + + if (data.depths.array[i].depth == 1) { + data.option |= fss_payload_read_data_option_extended_d; + } + + if (data.depth_max < data.depths.array[i].depth) { + data.depth_max = data.depths.array[i].depth; + } + } // for + + if (data.depth_max > 1) { + if (main->parameters[fss_payload_read_parameter_total_e].result == f_console_result_found_e) { + fss_payload_read_print_zero(main); + } + + fss_payload_read_data_delete_simple(&data); + fss_payload_read_main_delete(main); + + return F_none; + } + } + + if (F_status_is_error_not(status) && main->parameters[fss_payload_read_parameter_select_e].result == f_console_result_found_e) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sThe '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_read_long_select_s, main->error.notable); + fl_print_format("%[' parameter requires a positive number.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + + fss_payload_read_depths_resize(0, &data.depths); + + status = F_status_set_error(F_parameter); + } + + if (F_status_is_error_not(status)) { + for (f_array_length_t i = 0; i < data.files.used; ++i) { + macro_f_string_range_t_clear(data.files.array[i].range); + } // for + } + + if (F_status_is_error_not(status) && main->process_pipe) { + f_file_t file = f_file_t_initialize; + + file.id = F_type_descriptor_input_d; + file.stream = F_type_input_d; + + data.files.array[0].range.start = 0; + + status = f_file_stream_read(file, &data.buffer); + + if (F_status_is_error(status)) { + fll_error_file_print(main->error, F_status_set_fine(status), "f_file_stream_read", F_true, "-", "read", fll_error_file_type_pipe_e); + } + else if (data.buffer.used) { + data.files.array[0].range.stop = data.buffer.used - 1; + + // This standard is newline sensitive, when appending files to the buffer if the file lacks a final newline then this could break the format for files appended thereafter. + // Guarantee that a newline exists at the end of the buffer. + status = f_string_append_assure(f_string_eol_s, 1, &data.buffer); + + if (F_status_is_error(status)) { + fll_error_file_print(main->error, F_status_set_fine(status), "f_string_append_assure", F_true, "-", "read", fll_error_file_type_pipe_e); + } + } + else { + data.files.array[0].range.start = 1; + } + } + + if (F_status_is_error_not(status) && main->remaining.used > 0) { + f_file_t file = f_file_t_initialize; + f_array_length_t size_file = 0; + const f_array_length_t buffer_used = data.buffer.used; + uint16_t signal_check = 0; + + for (f_array_length_t i = 0; i < main->remaining.used; ++i) { + + if (!((++signal_check) % fss_payload_read_signal_check_d)) { + if (fss_payload_read_signal_received(main)) { + status = F_status_set_error(F_interrupt); + + break; + } + + signal_check = 0; + } + + data.files.array[data.files.used].range.start = data.buffer.used; + file.stream = 0; + file.id = -1; + + status = f_file_stream_open(arguments->argv[main->remaining.array[i]], 0, &file); + + if (F_status_is_error(status)) { + fll_error_file_print(main->error, F_status_set_fine(status), "f_file_stream_open", F_true, arguments->argv[main->remaining.array[i]], "open", fll_error_file_type_file_e); + + break; + } + + size_file = 0; + status = f_file_size_by_id(file.id, &size_file); + + if (F_status_is_error(status)) { + fll_error_file_print(main->error, F_status_set_fine(status), "f_file_size_by_id", F_true, arguments->argv[main->remaining.array[i]], "read", fll_error_file_type_file_e); + + break; + } + + if (size_file) { + status = f_string_dynamic_resize(data.buffer.size + size_file, &data.buffer); + + if (F_status_is_error(status)) { + fll_error_file_print(main->error, F_status_set_fine(status), "f_string_dynamic_resize", F_true, arguments->argv[main->remaining.array[i]], "read", fll_error_file_type_file_e); + + break; + } + + + // This standard is newline sensitive, when appending files to the buffer if the file lacks a final newline then this could break the format for files appended thereafter. + // Guarantee that a newline exists at the end of the buffer. + // This is done as a pre-process on the next file because the "payload" must always be last and must not have a newline appended. + if (buffer_used != data.buffer.used) { + status = f_string_append_assure(f_string_eol_s, 1, &data.buffer); + + if (F_status_is_error(status)) { + fll_error_file_print(main->error, F_status_set_fine(status), "f_string_append_assure", F_true, "-", "read", fll_error_file_type_pipe_e); + } + } + + status = f_file_stream_read(file, &data.buffer); + + if (F_status_is_error(status)) { + fll_error_file_print(main->error, F_status_set_fine(status), "f_file_stream_read", F_true, arguments->argv[main->remaining.array[i]], "read", fll_error_file_type_file_e); + + break; + } + else if (data.buffer.used > data.files.array[data.files.used].range.start) { + data.files.array[data.files.used].name = arguments->argv[main->remaining.array[i]]; + data.files.array[data.files.used++].range.stop = data.buffer.used - 1; + } + } + else { + data.files.array[data.files.used].range.start = 1; + } + + f_file_stream_close(F_true, &file); + } // for + + f_file_stream_close(F_true, &file); + } + + if (F_status_is_error_not(status)) { + status = fss_payload_read_process(main, arguments, &data); + } + + fss_payload_read_data_delete_simple(&data); + } + else { + fll_print_format("%c%[%sYou failed to specify one or more files.%]%c", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context, f_string_eol_s[0]); + status = F_status_set_error(F_parameter); + } + + if (main->error.verbosity != f_console_verbosity_quiet_e) { + if (F_status_set_fine(status) == F_interrupt) { + fflush(main->output.to.stream); + + fll_print_terminated(f_string_eol_s, main->output.to.stream); + } + } + + fss_payload_read_data_delete_simple(&data); + fss_payload_read_main_delete(main); + + return status; + } +#endif // _di_fss_payload_read_main_ + +#ifndef _di_fss_payload_read_main_delete_ + f_status_t fss_payload_read_main_delete(fss_payload_read_main_t * const main) { + + for (f_array_length_t i = 0; i < fss_payload_total_parameters_d; ++i) { + + macro_f_array_lengths_t_delete_simple(main->parameters[i].locations); + macro_f_array_lengths_t_delete_simple(main->parameters[i].locations_sub); + macro_f_array_lengths_t_delete_simple(main->parameters[i].values); + } // for + + macro_f_array_lengths_t_delete_simple(main->remaining); + macro_f_color_context_t_delete_simple(main->context); + + return F_none; + } +#endif // _di_fss_payload_read_main_delete_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_3/fss_payload_read/c/fss_payload_read.h b/level_3/fss_payload_read/c/fss_payload_read.h new file mode 100644 index 0000000..9f12ecf --- /dev/null +++ b/level_3/fss_payload_read/c/fss_payload_read.h @@ -0,0 +1,305 @@ +/** + * FLL - Level 3 + * + * Project: FSS + * API Version: 0.5 + * Licenses: lgpl-2.1-or-later + * + * 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_payload_read_main_t. + * + * This processes in accordance to the FSS-0002 Basic List specification. + */ +#ifndef _fss_payload_read_h + +// libc includes +#include +#include +#include +#include +#include + +// fll-0 includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// fll-1 includes +#include +#include +#include +#include + +// fll-2 includes +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fss_payload_read_program_version_ + #define fss_payload_program_version_major_s F_string_ascii_0_s + #define fss_payload_program_version_minor_s F_string_ascii_5_s + #define fss_payload_program_version_micro_s F_string_ascii_8_s + + #ifndef fss_payload_program_version_nano_prefix_s + #define fss_payload_program_version_nano_prefix_s + #endif + + #ifndef fss_payload_program_version_nano_s + #define fss_payload_program_version_nano_s + #endif + + #define fss_payload_program_version_s fss_payload_program_version_major_s F_string_ascii_period_s fss_payload_program_version_minor_s F_string_ascii_period_s fss_payload_program_version_micro_s fss_payload_program_version_nano_prefix_s fss_payload_program_version_nano_s +#endif // _di_fss_payload_read_program_version_ + +#ifndef _di_fss_payload_read_program_name_ + #define fss_payload_program_name_s "fss_payload_read" + #define fss_payload_program_name_long_s "FSS Basic List Read" +#endif // _di_fss_payload_read_program_name_ + +#ifndef _di_fss_payload_read_defines_ + #define fss_payload_read_signal_check_d 10000 + + #define fss_payload_read_pipe_content_end_s '\f' + #define fss_payload_read_pipe_content_ignore_s '\v' + #define fss_payload_read_pipe_content_start_s '\b' + + #define fss_payload_read_short_at_s "a" + #define fss_payload_read_short_content_s "c" + #define fss_payload_read_short_columns_s "C" + #define fss_payload_read_short_delimit_s "D" + #define fss_payload_read_short_depth_s "d" + #define fss_payload_read_short_empty_s "e" + #define fss_payload_read_short_line_s "l" + #define fss_payload_read_short_name_s "n" + #define fss_payload_read_short_object_s "o" + #define fss_payload_read_short_pipe_s "p" + #define fss_payload_read_short_raw_s "R" + #define fss_payload_read_short_select_s "s" + #define fss_payload_read_short_total_s "t" + #define fss_payload_read_short_trim_s "T" + + #define fss_payload_read_long_at_s "at" + #define fss_payload_read_long_content_s "content" + #define fss_payload_read_long_columns_s "columns" + #define fss_payload_read_long_delimit_s "delimit" + #define fss_payload_read_long_depth_s "depth" + #define fss_payload_read_long_empty_s "empty" + #define fss_payload_read_long_line_s "line" + #define fss_payload_read_long_name_s "name" + #define fss_payload_read_long_object_s "object" + #define fss_payload_read_long_pipe_s "pipe" + #define fss_payload_read_long_raw_s "raw" + #define fss_payload_read_long_select_s "select" + #define fss_payload_read_long_total_s "total" + #define fss_payload_read_long_trim_s "trim" + + enum { + fss_payload_read_parameter_help_e, + fss_payload_read_parameter_light_e, + fss_payload_read_parameter_dark_e, + fss_payload_read_parameter_no_color_e, + fss_payload_read_parameter_verbosity_quiet_e, + fss_payload_read_parameter_verbosity_normal_e, + fss_payload_read_parameter_verbosity_verbose_e, + fss_payload_read_parameter_verbosity_debug_e, + fss_payload_read_parameter_version_e, + + fss_payload_read_parameter_at_e, + fss_payload_read_parameter_content_e, + fss_payload_read_parameter_columns_e, + fss_payload_read_parameter_delimit_e, + fss_payload_read_parameter_depth_e, + fss_payload_read_parameter_empty_e, + fss_payload_read_parameter_line_e, + fss_payload_read_parameter_name_e, + fss_payload_read_parameter_object_e, + fss_payload_read_parameter_pipe_e, + fss_payload_read_parameter_raw_e, + fss_payload_read_parameter_select_e, + fss_payload_read_parameter_total_e, + fss_payload_read_parameter_trim_e, + }; + + #define fss_payload_read_console_parameter_t_initialize \ + { \ + f_console_parameter_t_initialize(f_console_standard_short_help_s, f_console_standard_long_help_s, 0, 0, f_console_type_normal_e), \ + f_console_parameter_t_initialize(f_console_standard_short_light_s, f_console_standard_long_light_s, 0, 0, f_console_type_inverse_e), \ + f_console_parameter_t_initialize(f_console_standard_short_dark_s, f_console_standard_long_dark_s, 0, 0, f_console_type_inverse_e), \ + f_console_parameter_t_initialize(f_console_standard_short_no_color_s, f_console_standard_long_no_color_s, 0, F_false, f_console_type_inverse_e), \ + f_console_parameter_t_initialize(f_console_standard_short_quiet_s, f_console_standard_long_quiet_s, 0, 0, f_console_type_inverse_e), \ + f_console_parameter_t_initialize(f_console_standard_short_normal_s, f_console_standard_long_normal_s, 0, 0, f_console_type_inverse_e), \ + f_console_parameter_t_initialize(f_console_standard_short_verbose_s, f_console_standard_long_verbose_s, 0, 0, f_console_type_inverse_e), \ + f_console_parameter_t_initialize(f_console_standard_short_debug_s, f_console_standard_long_debug_s, 0, 0, f_console_type_inverse_e), \ + f_console_parameter_t_initialize(f_console_standard_short_version_s, f_console_standard_long_version_s, 0, 0, f_console_type_inverse_e), \ + f_console_parameter_t_initialize(fss_payload_read_short_at_s, fss_payload_read_long_at_s, 0, 1, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_read_short_content_s, fss_payload_read_long_content_s, 0, 0, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_read_short_columns_s, fss_payload_read_long_columns_s, 0, 0, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_read_short_delimit_s, fss_payload_read_long_delimit_s, 0, 1, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_read_short_depth_s, fss_payload_read_long_depth_s, 0, 1, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_read_short_empty_s, fss_payload_read_long_empty_s, 0, 0, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_read_short_line_s, fss_payload_read_long_line_s, 0, 1, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_read_short_name_s, fss_payload_read_long_name_s, 0, 1, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_read_short_object_s, fss_payload_read_long_object_s, 0, 0, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_read_short_pipe_s, fss_payload_read_long_pipe_s, 0, 0, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_read_short_raw_s, fss_payload_read_long_raw_s, 0, 0, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_read_short_select_s, fss_payload_read_long_select_s, 0, 1, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_read_short_total_s, fss_payload_read_long_total_s, 0, 0, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_read_short_trim_s, fss_payload_read_long_trim_s, 0, 0, f_console_type_normal_e), \ + } + + #define fss_payload_total_parameters_d 23 +#endif // _di_fss_payload_read_defines_ + +/** + * FSS Delimit Parameter data. + * + * fss_payload_read_delimit_mode_*: + * - all: All delimits are to be aplied. + * - content: Content are to have delimits applied. + * - content_greater: Content at this number or higher are to have delimits applied. + * - content_greater_object: Objects and Content at this number or higher are to have delimits applied. + * - content_lesser: Content at this number or lower are to have delimits applied. + * - content_lesser_object: Objects and Content at this number or lower are to have delimits applied. + * - content_object: Objects and Content are to have delimits applied + * - object: Objects arre to have delimits applied. + */ +#ifndef _di_fss_payload_read_delimit_mode_ + #define fss_payload_read_delimit_mode_name_none_s "none" + #define fss_payload_read_delimit_mode_name_all_s "all" + #define fss_payload_read_delimit_mode_name_object_s "object" + #define fss_payload_read_delimit_mode_name_greater_s "+" + #define fss_payload_read_delimit_mode_name_lesser_s "-" + + #define fss_payload_read_delimit_mode_name_none_s_length 4 + #define fss_payload_read_delimit_mode_name_all_s_length 3 + #define fss_payload_read_delimit_mode_name_object_s_length 6 + #define fss_payload_read_delimit_mode_name_greater_s_length 1 + #define fss_payload_read_delimit_mode_name_lesser_s_length 1 + + enum { + fss_payload_read_delimit_mode_none_e = 1, + fss_payload_read_delimit_mode_all_e, + fss_payload_read_delimit_mode_content_e, + fss_payload_read_delimit_mode_content_greater_e, + fss_payload_read_delimit_mode_content_greater_object_e, + fss_payload_read_delimit_mode_content_lesser_e, + fss_payload_read_delimit_mode_content_lesser_object_e, + fss_payload_read_delimit_mode_content_object_e, + fss_payload_read_delimit_mode_object_e, + }; +#endif // _di_fss_payload_read_delimit_modes_ + +#ifndef _di_fss_payload_read_main_t_ + typedef struct { + f_console_parameter_t parameters[fss_payload_total_parameters_d]; + + f_array_lengths_t remaining; + bool process_pipe; + + fl_print_t output; + fl_print_t error; + fl_print_t warning; + + f_signal_t signal; + + f_color_context_t context; + } fss_payload_read_main_t; + + #define fss_payload_read_main_t_initialize \ + { \ + fss_payload_read_console_parameter_t_initialize, \ + f_array_lengths_t_initialize, \ + F_false, \ + fl_print_t_initialize, \ + macro_fl_print_t_initialize_error(), \ + macro_fl_print_t_initialize_warning(), \ + f_signal_t_initialize, \ + f_color_context_t_initialize, \ + } +#endif // _di_fss_payload_read_main_t_ + +/** + * Print help. + * + * @param file + * The file to print to. + * @param context + * The color context settings. + * + * @return + * F_none on success. + */ +#ifndef _di_fss_payload_read_print_help_ + extern f_status_t fss_payload_read_print_help(const f_file_t file, const f_color_context_t context); +#endif // _di_fss_payload_read_print_help_ + +/** + * Execute main program. + * + * Be sure to call fss_payload_read_main_delete() after executing this. + * + * If main.signal is non-zero, then this blocks and handles the following signals: + * - F_signal_abort + * - F_signal_broken_pipe + * - F_signal_hangup + * - F_signal_interrupt + * - F_signal_quit + * - F_signal_termination + * + * @param arguments + * The parameters passed to the process. + * @param main + * The main program data. + * + * @return + * F_none on success. + * + * Status codes (with error bit) are returned on any problem. + * + * @see fss_payload_read_main_delete() + */ +#ifndef _di_fss_payload_read_main_ + extern f_status_t fss_payload_read_main(fss_payload_read_main_t * const main, const f_console_arguments_t *arguments); +#endif // _di_fss_payload_read_main_ + +/** + * Deallocate main. + * + * Be sure to call this after executing fss_payload_read_main(). + * + * @param main + * The main program data. + * + * @return + * F_none on success. + * + * Status codes (with error bit) are returned on any problem. + * + * @see fss_payload_read_main() + */ +#ifndef _di_fss_payload_read_main_delete_ + extern f_status_t fss_payload_read_main_delete(fss_payload_read_main_t * const main); +#endif // _di_fss_payload_read_main_delete_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _fss_payload_read_h diff --git a/level_3/fss_payload_read/c/main.c b/level_3/fss_payload_read/c/main.c new file mode 100644 index 0000000..f5caeb2 --- /dev/null +++ b/level_3/fss_payload_read/c/main.c @@ -0,0 +1,53 @@ +#include "fss_payload_read.h" + +int main(const int argc, const f_string_t *argv) { + + f_console_arguments_t arguments = { argc, argv }; + fss_payload_read_main_t data = fss_payload_read_main_t_initialize; + + if (f_pipe_input_exists()) { + data.process_pipe = F_true; + } + + // Handle signals so that program can cleanly exit, deallocating as appropriate. + { + f_signal_set_empty(&data.signal.set); + f_signal_set_add(F_signal_abort, &data.signal.set); + f_signal_set_add(F_signal_broken_pipe, &data.signal.set); + f_signal_set_add(F_signal_hangup, &data.signal.set); + f_signal_set_add(F_signal_interrupt, &data.signal.set); + f_signal_set_add(F_signal_quit, &data.signal.set); + f_signal_set_add(F_signal_termination, &data.signal.set); + + f_status_t status = f_signal_mask(SIG_BLOCK, &data.signal.set, 0); + + if (F_status_is_error_not(status)) { + status = f_signal_open(&data.signal); + + // If there is an error opening a signal descriptor, then do not handle signals. + if (F_status_is_error(status)) { + f_signal_mask(SIG_UNBLOCK, &data.signal.set, 0); + f_signal_close(&data.signal); + } + } + } + + const f_status_t status = fss_payload_read_main(&data, &arguments); + + // Flush output pipes before closing. + fflush(F_type_output_d); + fflush(F_type_error_d); + + // Close all open file descriptors. + close(F_type_descriptor_output_d); + close(F_type_descriptor_input_d); + close(F_type_descriptor_error_d); + + f_signal_close(&data.signal); + + if (F_status_is_error(status)) { + return 1; + } + + return 0; +} diff --git a/level_3/fss_payload_read/c/private-common.c b/level_3/fss_payload_read/c/private-common.c new file mode 100644 index 0000000..d61200e --- /dev/null +++ b/level_3/fss_payload_read/c/private-common.c @@ -0,0 +1,115 @@ +#include "fss_payload_read.h" +#include "private-common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fss_payload_read_data_delete_simple_ + void fss_payload_read_data_delete_simple(fss_payload_read_data_t *data) { + + if (!data) return; + + // data->files is expected to be statically loaded and cannot be deallocated. + + fss_payload_read_depths_resize(0, &data->depths); + + macro_f_string_dynamic_t_delete_simple(data->buffer); + macro_f_fss_contents_t_delete_simple(data->contents); + macro_f_fss_contents_t_delete_simple(data->contents_header); + macro_f_fss_objects_t_delete_simple(data->objects); + macro_f_fss_objects_t_delete_simple(data->objects_header); + macro_f_fss_quotes_t_delete_simple(data->quotes_object_header); + macro_f_fss_quotess_t_delete_simple(data->quotes_content_header); + macro_f_fss_delimits_t_delete_simple(data->delimits_object); + macro_f_fss_delimits_t_delete_simple(data->delimits_object_header); + macro_f_fss_delimits_t_delete_simple(data->delimits_content); + macro_f_fss_delimits_t_delete_simple(data->delimits_content_header); + macro_f_fss_comments_t_delete_simple(data->comments); + } +#endif // _di_fss_payload_read_data_delete_simple_ + +#ifndef _di_fss_payload_read_depth_delete_simple_ + void fss_payload_read_depth_delete_simple(fss_payload_read_depth_t *depth) { + + if (!depth) return; + + f_string_dynamic_resize(0, &depth->value_name); + } +#endif // _di_fss_payload_read_depth_delete_simple_ + +#ifndef _di_fss_payload_read_depths_resize_ + f_status_t fss_payload_read_depths_resize(const f_array_length_t length, fss_payload_read_depths_t *depths) { + + if (!depths) { + return F_status_set_error(F_parameter); + } + + for (f_array_length_t i = length; i < depths->size; ++i) { + fss_payload_read_depth_delete_simple(&depths->array[i]); + } // for + + const f_status_t status = f_memory_resize(depths->size, length, sizeof(fss_payload_read_depth_t), (void **) & depths->array); + + if (F_status_is_error_not(status)) { + depths->size = length; + + if (depths->used > depths->size) { + depths->used = length; + } + } + + return status; + } +#endif // _di_fss_payload_read_depths_resize_ + +#ifndef _di_fss_payload_read_print_signal_received_ + void fss_payload_read_print_signal_received(fss_payload_read_main_t * const main, const f_status_t signal) { + + if (main->warning.verbosity != f_console_verbosity_verbose_e) return; + + // Must flush and reset color because the interrupt may have interrupted the middle of a print function. + fflush(main->warning.to.stream); + + flockfile(main->warning.to.stream); + + fl_print_format("%]%c%c%[Received signal code %]", main->warning.to.stream, main->context.set.reset, f_string_eol_s[0], f_string_eol_s[0], main->context.set.warning, main->context.set.warning); + fl_print_format("%[%i%]", main->warning.to.stream, main->context.set.notable, signal, main->context.set.notable); + fl_print_format("%[.%]%c", main->warning.to.stream, main->context.set.warning, main->context.set.warning, f_string_eol_s[0]); + + funlockfile(main->warning.to.stream); + } +#endif // _di_fss_payload_read_print_signal_received_ + +#ifndef _di_fss_payload_read_signal_received_ + f_status_t fss_payload_read_signal_received(fss_payload_read_main_t * const main) { + + if (main->signal.id == -1) { + return F_false; + } + + struct signalfd_siginfo information; + + memset(&information, 0, sizeof(struct signalfd_siginfo)); + + if (f_signal_read(main->signal, 0, &information) == F_signal) { + switch (information.ssi_signo) { + case F_signal_abort: + case F_signal_broken_pipe: + case F_signal_hangup: + case F_signal_interrupt: + case F_signal_quit: + case F_signal_termination: + fss_payload_read_print_signal_received(main, information.ssi_signo); + + return information.ssi_signo; + } + } + + return F_false; + } +#endif // _di_fss_payload_read_signal_received_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_3/fss_payload_read/c/private-common.h b/level_3/fss_payload_read/c/private-common.h new file mode 100644 index 0000000..13ab8fa --- /dev/null +++ b/level_3/fss_payload_read/c/private-common.h @@ -0,0 +1,305 @@ +/** + * FLL - Level 3 + * + * Project: FSS Basic List Read + * API Version: 0.5 + * Licenses: lgpl-2.1-or-later + */ +#ifndef _PRIVATE_common_h +#define _PRIVATE_common_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Provide common/generic definitions. + * + * payload_read_common_allocation_*: + * - large: An allocation step used for buffers that are anticipated to have large buffers. + * - small: An allocation step used for buffers that are anticipated to have small buffers. + */ +#ifndef _di_fss_payload_read_common_ + #define fss_payload_common_allocation_large_d 256 + #define fss_payload_read_common_allocation_small_d 16 +#endif // _di_fss_payload_read_common_ + +/** + * 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_payload_read_depth_t_ + typedef struct { + f_array_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_payload_read_depth_t; + + #define fss_payload_read_depth_t_initialize \ + { \ + 0, \ + 0, \ + 0, \ + 0, \ + f_string_dynamic_t_initialize, \ + } + + #define macro_fss_payload_read_depth_t_clear(structure) \ + structure.depth = 0; \ + structure.index_at = 0; \ + structure.index_name = 0; \ + structure.value_at = 0; \ + macro_f_string_dynamic_t_clear(structure.value_name) +#endif // _di_fss_payload_read_depth_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_payload_read_depths_t_ + typedef struct { + fss_payload_read_depth_t *array; + + f_array_length_t size; + f_array_length_t used; + } fss_payload_read_depths_t; + + #define fss_payload_read_depths_t_initialize { 0, 0, 0 } + + #define macro_fss_payload_read_depths_t_clear(depths) macro_f_memory_structure_clear(depths) +#endif // _di_fss_payload_read_depths_t_ + +/** + * A structure for designating where within the buffer a particular file exists, using a statically allocated array. + * + * name: The name of the file representing the range. Set string to NULL to represent the STDIN pipe. + * range: A range within the buffer representing the file. + */ +#ifndef _di_fss_payload_read_file_t_ + typedef struct { + f_string_t name; + f_string_range_t range; + } fss_payload_read_file_t; + + #define fss_payload_read_file_t_initialize \ + { \ + f_string_t_initialize, \ + f_string_range_t_initialize, \ + } +#endif // _di_fss_payload_read_file_t_ + +/** + * An array of files. + * + * This is intended to be defined and used statically allocated and as such no dynamic allocation or dynamic deallocation methods are provided. + * + * The STDIN pipe is reserved for index 0 and as such size and used must be initialized to 1. + * + * array: The array of depths. + * size: Total amount of allocated space. + * used: Total number of allocated spaces used. + */ +#ifndef _di_fss_payload_read_files_t_ + typedef struct { + fss_payload_read_file_t *array; + + f_array_length_t size; + f_array_length_t used; + } fss_payload_read_files_t; + + #define fss_payload_read_files_t_initialize { 0, 1, 1 } +#endif // _di_fss_payload_read_files_t_ + +/** + * The data structure for FSS Basic Read. + * + * fss_payload_read_data_option_*: + * - at: The object at the given position is being selected (Think of this as select a row for some Object). + * - columns: The total columns found and selected is printed instead of the Content. + * - content: The Content is to be printed. + * - empty: Empty Content will be printed (Objects that have no Content will have their empty Content printed). + * - extended: Based on the depth, the extended list is to be processed. + * - line: A specific Content at a given line is to be selected (Think of this as select a row for some Content). + * - name: A specific Object name has been requested. + * - object: The Object is to be printed. + * - raw: Enable raw printing, where the quotes are printed and no delimits are applied. + * - select: A specific Content at a given position is to be selected (Think of this as select a column for some Content). + * - total: The total lines found and selected is printed instead of the Content. + * - trim: Empty space before and after Objects and Content will not be printed (They will be trimmed). + * + * options: Bitwise flags representing parameters. + * delimit_mode: The delimit mode. + * delimit_depth: The delimit depth. + * select: The Content to select (column number). + * line: The Content to select (row number). + * files: A statically allocated array of files for designating where in the buffer a file is represented. + * depths: The array of parameters for each given depth. + * buffer: The buffer containing all loaded files (and STDIN pipe). + * objects: The positions within the buffer representing Objects. + * objects_header: The positions within the buffer representing header Objects. + * contents: The positions within the buffer representing Contents. + * contents_header: The positions within the buffer representing header Contents. + * delimits_object: The positions within the buffer representing Object character delimits. + * delimits_object_header: The positions within the buffer representing header Object character delimits. + * delimits_content: The positions within the buffer representing Content character delimits. + * delimits_content_header: The positions within the buffer representing header Content character delimits. + */ +#ifndef _di_fss_payload_read_data_t_ + #define fss_payload_read_data_option_at_d 0x1 + #define fss_payload_read_data_option_columns_d 0x2 + #define fss_payload_read_data_option_content_d 0x4 + #define fss_payload_read_data_option_empty_d 0x8 + #define fss_payload_read_data_option_extended_d 0x10 + #define fss_payload_read_data_option_line_d 0x20 + #define fss_payload_read_data_option_name_d 0x40 + #define fss_payload_read_data_option_object_d 0x80 + #define fss_payload_read_data_option_raw_d 0x100 + #define fss_payload_read_data_option_select_d 0x200 + #define fss_payload_read_data_option_total_d 0x400 + #define fss_payload_read_data_option_trim_d 0x800 + + typedef struct { + uint16_t option; + uint8_t delimit_mode; + f_array_length_t depth_max; + f_array_length_t delimit_depth; + f_number_unsigned_t select; + f_number_unsigned_t line; + + fss_payload_read_files_t files; + fss_payload_read_depths_t depths; + + f_string_dynamic_t buffer; + f_fss_objects_t objects; + f_fss_objects_t objects_header; + f_fss_contents_t contents; + f_fss_contents_t contents_header; + f_fss_quotes_t quotes_object_header; + f_fss_quotess_t quotes_content_header; + f_fss_delimits_t delimits_object; + f_fss_delimits_t delimits_object_header; + f_fss_delimits_t delimits_content; + f_fss_delimits_t delimits_content_header; + f_fss_comments_t comments; + f_fss_quotes_t quotes; + } fss_payload_read_data_t; + + #define fss_payload_read_data_t_initialize \ + { \ + 0, \ + fss_payload_read_delimit_mode_all_e, \ + 0, \ + 0, \ + 0, \ + 0, \ + fss_payload_read_files_t_initialize, \ + fss_payload_read_depths_t_initialize, \ + f_string_dynamic_t_initialize, \ + f_fss_objects_t_initialize, \ + f_fss_objects_t_initialize, \ + f_fss_contents_t_initialize, \ + f_fss_contents_t_initialize, \ + f_fss_quotes_t_initialize, \ + f_fss_quotess_t_initialize, \ + f_fss_delimits_t_initialize, \ + f_fss_delimits_t_initialize, \ + f_fss_delimits_t_initialize, \ + f_fss_delimits_t_initialize, \ + f_fss_quotes_t_initialize, \ + f_fss_comments_t_initialize, \ + } +#endif // _di_fss_payload_read_data_t_ + +/** + * Fully deallocate all memory for the given data without caring about return status. + * + * @param data + * The data to deallocate. + */ +#ifndef _di_fss_payload_read_data_delete_simple_ + extern void fss_payload_read_data_delete_simple(fss_payload_read_data_t *data) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_data_delete_simple_ + +/** + * Fully deallocate all memory for the given depth without caring about return status. + * + * @param depth + * The depth to deallocate. + */ +#ifndef _di_fss_payload_read_depth_delete_simple_ + extern void fss_payload_read_depth_delete_simple(fss_payload_read_depth_t *depth) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_depth_delete_simple_ + +/** + * Resize the depth array. + * + * @param length + * The new size to use. + * @param depths + * The depth array to resize. + * + * @return + * F_none on success. + * + * Errors (with error bit) from: f_memory_resize(). + * + * Errors (with error bit) from: fss_payload_read_depths_increase(). + * + * @see f_memory_resize() + * + * @see fss_payload_read_depth_delete_simple() + * @see fss_payload_read_depths_increase() + */ +#ifndef _di_fss_payload_read_depths_resize_ + extern f_status_t fss_payload_read_depths_resize(const f_array_length_t length, fss_payload_read_depths_t *depths) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_depths_resize_ + +/** + * Print a message about a process signal being recieved, such as an interrupt signal. + * + * @param main + * The main program data. + * @param signal + * The signal received. + */ +#ifndef _di_fss_payload_read_print_signal_received_ + extern void fss_payload_read_print_signal_received(fss_payload_read_main_t * const main, const f_status_t signal) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_print_signal_received_ + +/** + * Check to see if a process signal is received. + * + * Only signals that are blocked via main.signal will be received. + * + * @param main + * The main program data. + * + * @return + * A positive number representing a valid signal on signal received. + * F_false on no signal received. + * + * @see f_signal_read() + */ +#ifndef _di_fss_payload_read_signal_received_ + extern f_status_t fss_payload_read_signal_received(fss_payload_read_main_t * const main) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_signal_received_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _PRIVATE_common_h diff --git a/level_3/fss_payload_read/c/private-fss_payload_read.c b/level_3/fss_payload_read/c/private-fss_payload_read.c new file mode 100644 index 0000000..6da1a81 --- /dev/null +++ b/level_3/fss_payload_read/c/private-fss_payload_read.c @@ -0,0 +1,1497 @@ +#include "fss_payload_read.h" +#include "private-common.h" +#include "private-fss_payload_read.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fss_payload_read_delimit_content_is_ + f_status_t fss_payload_read_delimit_content_is(const f_array_length_t depth, fss_payload_read_data_t * const data) { + + if (data->delimit_mode == fss_payload_read_delimit_mode_none_e) { + return F_false; + } + + if (data->delimit_mode == fss_payload_read_delimit_mode_all_e) { + return F_true; + } + + if (depth < data->delimit_depth) { + return data->delimit_mode == fss_payload_read_delimit_mode_content_lesser_e; + } + + if (depth == data->delimit_depth) { + return F_true; + } + + return data->delimit_mode == fss_payload_read_delimit_mode_content_greater_e; + } +#endif // _di_fss_payload_read_delimit_content_is_ + +#ifndef _di_fss_payload_read_delimit_object_is_ + f_status_t fss_payload_read_delimit_object_is(const f_array_length_t depth, fss_payload_read_data_t * const data) { + + switch (data->delimit_mode) { + case fss_payload_read_delimit_mode_none_e: + case fss_payload_read_delimit_mode_content_e: + case fss_payload_read_delimit_mode_content_greater_e: + case fss_payload_read_delimit_mode_content_lesser_e: + return F_false; + + case fss_payload_read_delimit_mode_all_e: + case fss_payload_read_delimit_mode_content_object_e: + case fss_payload_read_delimit_mode_content_greater_object_e: + case fss_payload_read_delimit_mode_content_lesser_object_e: + case fss_payload_read_delimit_mode_object_e: + return F_true; + + default: + break; + } + + return depth == data->delimit_depth || data->delimit_mode == fss_payload_read_delimit_mode_content_lesser_e; + } +#endif // _di_fss_payload_read_delimit_object_is_ + +#ifndef _di_fss_payload_read_depth_process_ + f_status_t fss_payload_read_depth_process(fss_payload_read_main_t * const main, const f_console_arguments_t *arguments, fss_payload_read_data_t *data) { + + f_status_t status = F_none; + + { + f_array_length_t depth_size = 1; + + if (main->parameters[fss_payload_read_parameter_depth_e].result == f_console_result_additional_e) { + depth_size = main->parameters[fss_payload_read_parameter_depth_e].values.used; + } + + if (depth_size > data->depths.size) { + status = fss_payload_read_depths_resize(depth_size, &data->depths); + + if (F_status_is_error(status)) { + fll_error_print(main->error, F_status_set_fine(status), "fss_payload_read_depths_resize", F_true); + + return status; + } + } + + data->depths.used = depth_size; + } + + f_array_length_t position_depth = 0; + f_array_length_t position_at = 0; + f_array_length_t position_name = 0; + uint16_t signal_check = 0; + + for (f_array_length_t i = 0; i < data->depths.used; ++i) { + + if (!((++signal_check) % fss_payload_read_signal_check_d)) { + if (fss_payload_read_signal_received(main)) { + return F_status_set_error(F_interrupt); + } + + signal_check = 0; + } + + data->depths.array[i].depth = 0; + data->depths.array[i].index_at = 0; + data->depths.array[i].index_name = 0; + data->depths.array[i].value_at = 0; + + macro_f_string_dynamic_t_clear(data->depths.array[i].value_name); + + if (!main->parameters[fss_payload_read_parameter_depth_e].values.used) { + position_depth = 0; + } + else { + position_depth = main->parameters[fss_payload_read_parameter_depth_e].values.array[i]; + + const f_string_range_t range = macro_f_string_range_t_initialize(strlen(arguments->argv[position_depth])); + + status = fl_conversion_string_to_number_unsigned(arguments->argv[position_depth], range, &data->depths.array[i].depth); + + if (F_status_is_error(status)) { + fll_error_parameter_integer_print(main->error, F_status_set_fine(status), "fl_conversion_string_to_number_unsigned", F_true, fss_payload_read_long_depth_s, arguments->argv[position_depth]); + + return status; + } + } + + if (main->parameters[fss_payload_read_parameter_at_e].result == f_console_result_additional_e) { + for (; position_at < main->parameters[fss_payload_read_parameter_at_e].values.used; ++position_at) { + + if (main->parameters[fss_payload_read_parameter_at_e].values.array[position_at] < position_depth) { + continue; + } + + if (i + 1 < data->depths.used && main->parameters[fss_payload_read_parameter_at_e].values.array[position_at] > main->parameters[fss_payload_read_parameter_depth_e].values.array[i + 1]) { + break; + } + + data->depths.array[i].index_at = main->parameters[fss_payload_read_parameter_at_e].values.array[position_at]; + + const f_string_range_t range = macro_f_string_range_t_initialize(strlen(arguments->argv[data->depths.array[i].index_at])); + + status = fl_conversion_string_to_number_unsigned(arguments->argv[data->depths.array[i].index_at], range, &data->depths.array[i].value_at); + + if (F_status_is_error(status)) { + fll_error_parameter_integer_print(main->error, F_status_set_fine(status), "fl_conversion_string_to_number_unsigned", F_true, fss_payload_read_long_at_s, arguments->argv[data->depths.array[i].index_at]); + + return status; + } + } // for + } + + if (main->parameters[fss_payload_read_parameter_name_e].result == f_console_result_additional_e) { + for (; position_name < main->parameters[fss_payload_read_parameter_name_e].values.used; ++position_name) { + + if (main->parameters[fss_payload_read_parameter_name_e].values.array[position_name] < position_depth) { + continue; + } + + if (i + 1 < data->depths.used && main->parameters[fss_payload_read_parameter_name_e].values.array[position_name] > main->parameters[fss_payload_read_parameter_depth_e].values.array[i + 1]) { + break; + } + + data->depths.array[i].index_name = main->parameters[fss_payload_read_parameter_name_e].values.array[position_name]; + + if (main->parameters[fss_payload_read_parameter_trim_e].result == f_console_result_found_e) { + status = fl_string_rip(arguments->argv[data->depths.array[i].index_name], strlen(arguments->argv[data->depths.array[i].index_name]), &data->depths.array[i].value_name); + } + else { + status = f_string_append(arguments->argv[data->depths.array[i].index_name], strlen(arguments->argv[data->depths.array[i].index_name]), &data->depths.array[i].value_name); + } + + if (F_status_is_error(status)) { + fll_error_print(main->error, F_status_set_fine(status), main->parameters[fss_payload_read_parameter_trim_e].result == f_console_result_found_e ? "fl_string_rip" : "f_string_append", F_true); + + return status; + } + } // for + } + } // for + + for (f_array_length_t i = 0; i < data->depths.used; ++i) { + + for (f_array_length_t j = i + 1; j < data->depths.used; ++j) { + + if (!((++signal_check) % fss_payload_read_signal_check_d)) { + if (fss_payload_read_signal_received(main)) { + return F_status_set_error(F_interrupt); + } + + signal_check = 0; + } + + if (data->depths.array[i].depth == data->depths.array[j].depth) { + if (main->error.verbosity != f_console_verbosity_quiet_e) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sThe value '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%ul%]", main->error.to.stream, main->error.notable, data->depths.array[i].depth, main->error.notable); + fl_print_format("%[' may only be specified once for the parameter '%]", main->error.to.stream, main->error.context, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_read_long_depth_s, main->error.notable); + fl_print_format("%['.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } + + return F_status_set_error(F_parameter); + } + else if (data->depths.array[i].depth > data->depths.array[j].depth) { + if (main->error.verbosity != f_console_verbosity_quiet_e) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sThe parameter '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_read_long_depth_s, main->error.notable); + fl_print_format("%[' may not have the value '%]", main->error.to.stream, main->error.context, main->error.context); + fl_print_format("%[%ul%]", main->error.to.stream, main->error.notable, data->depths.array[i].depth, main->error.notable); + fl_print_format("%[' before the value '%]", main->error.to.stream, main->error.context, main->error.context); + fl_print_format("%[%ul%]", main->error.to.stream, main->error.notable, data->depths.array[j].depth, main->error.notable); + fl_print_format("%['.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } + + return F_status_set_error(F_parameter); + } + } // for + } // for + + return F_none; + } +#endif // _di_fss_payload_read_depth_process_ + +#ifndef _di_fss_payload_read_file_identify_ + f_string_t fss_payload_read_file_identify(const f_array_length_t at, const fss_payload_read_files_t files) { + + for (f_array_length_t i = 0; i < files.used; ++i) { + + if (at >= files.array[i].range.start && at <= files.array[i].range.stop) { + return files.array[i].name; + } + } // for + + // When stopped after the end of the buffer, the last file in the list is the correct file. + if (at > files.array[files.used - 1].range.stop) { + return files.array[files.used - 1].name; + } + + return ""; + } +#endif // _di_fss_payload_read_file_identify_ + +#ifndef _di_fss_payload_read_load_ + f_status_t fss_payload_read_load(fss_payload_read_main_t * const main, fss_payload_read_data_t *data) { + + f_state_t state = macro_f_state_t_initialize(fss_payload_common_allocation_large_d, fss_payload_read_common_allocation_small_d, 0, 0, 0, 0, 0); + f_string_range_t input = macro_f_string_range_t_initialize(data->buffer.used); + + data->delimits_object.used = 0; + data->delimits_content.used = 0; + + f_status_t status = fll_fss_payload_read(data->buffer, state, &input, &data->objects, &data->contents, &data->delimits_object, &data->delimits_content, &data->comments); + + if (F_status_is_error(status)) { + const f_string_t file_name = fss_payload_read_file_identify(input.start, data->files); + + if (F_status_set_fine(status) == F_none || F_status_set_fine(status) == F_none_eos || F_status_set_fine(status) == F_none_stop || F_status_set_fine(status) == F_data_not_eos || F_status_set_fine(status) == F_data_not_stop) { + if (main->error.verbosity != f_console_verbosity_quiet_e) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sThe file '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%]", main->error.to.stream, main->error.notable, file_name, main->error.notable); + fl_print_format("%[' does not have the required Object '%]", main->error.to.stream, main->error.context, main->error.context); + fl_print_format("%[%s%]", main->error.to.stream, main->error.notable, F_fss_string_payload_s, main->error.notable); + fl_print_format("%['.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } + } + else { + fll_error_file_print(main->error, F_status_set_fine(status), "fll_fss_payload_read", F_true, file_name, "process", fll_error_file_type_file_e); + } + + return status; + } + + if (status == F_data_not_stop || status == F_data_not_eos) { + if (data->option & fss_payload_read_data_option_total_d) { + flockfile(main->output.to.stream); + + fss_payload_read_print_zero(main); + + funlockfile(main->output.to.stream); + + return F_none; + } + + return F_status_set_warning(status); + } + + // Load the "header" information. + for (f_array_length_t i = 0; i < data->objects.used; ++i) { + + if (fl_string_dynamic_partial_compare_string(F_fss_string_header_s, data->buffer, F_fss_string_header_s_length, data->objects.array[i]) == F_equal_to) { + f_string_range_t input_header = data->contents.array[i].array[0]; + + status = fll_fss_extended_read(data->buffer, state, &input_header, &data->objects_header, &data->contents_header, &data->quotes_object_header, &data->quotes_content_header, &data->delimits_object_header, &data->delimits_content_header); + + if (F_status_is_error(status)) { + const f_string_t file_name = fss_payload_read_file_identify(input.start, data->files); + + fll_error_file_print(main->error, F_status_set_fine(status), "fll_fss_extended_read", F_true, file_name, "process", fll_error_file_type_file_e); + + return status; + } + } + } // for + + return F_none; + } +#endif // _di_fss_payload_read_load_ + +#ifndef _di_fss_payload_read_load_number_ + f_status_t fss_payload_read_load_number(fss_payload_read_main_t * const main, const f_array_length_t parameter, const f_string_t name, const f_console_arguments_t *arguments, f_number_unsigned_t *number) { + + if (main->parameters[parameter].result == f_console_result_additional_e) { + const f_array_length_t index = main->parameters[parameter].values.array[main->parameters[parameter].values.used - 1]; + const f_string_range_t range = macro_f_string_range_t_initialize(strnlen(arguments->argv[index], f_console_parameter_size)); + + const f_status_t status = fl_conversion_string_to_number_unsigned(arguments->argv[index], range, number); + + if (F_status_is_error(status)) { + fll_error_parameter_integer_print(main->error, F_status_set_fine(status), "fl_conversion_string_to_number_unsigned", F_true, name, arguments->argv[index]); + + return status; + } + + return F_true; + } + + return F_false; + } +#endif // _di_fss_payload_read_load_number_ + +#ifndef _di_fss_payload_read_print_at_ + void fss_payload_read_print_at(fss_payload_read_main_t * const main, const bool is_payload, const f_array_length_t at, const f_fss_delimits_t delimits_object, const f_fss_delimits_t delimits_content, fss_payload_read_data_t * const data) { + + if (at >= data->contents.used) { + return; + } + + if ((data->option & fss_payload_read_data_option_object_d) || (data->option & fss_payload_read_data_option_content_d) && (data->contents.array[at].used || (data->option & fss_payload_read_data_option_empty_d))) { + flockfile(main->output.to.stream); + + if (data->option & fss_payload_read_data_option_object_d) { + if (data->option & fss_payload_read_data_option_trim_d) { + fl_print_trim_except_in_dynamic_partial(data->buffer, data->objects.array[at], delimits_object, data->comments, main->output.to.stream); + } + else { + f_print_except_in_dynamic_partial(data->buffer, data->objects.array[at], delimits_object, data->comments, main->output.to.stream); + } + + fss_payload_read_print_object_end(main); + } + + if (data->option & fss_payload_read_data_option_content_d) { + if (data->contents.array[at].used) { + if (!is_payload) { + fss_payload_read_print_content_ignore(main); + } + + if (is_payload) { + f_print_dynamic_partial_raw(data->buffer, data->contents.array[at].array[0], main->output.to.stream); + } + else { + f_print_except_in_dynamic_partial(data->buffer, data->contents.array[at].array[0], delimits_content, data->comments, main->output.to.stream); + } + + if (!is_payload) { + fss_payload_read_print_content_ignore(main); + } + } + } + + if (!is_payload) { + fss_payload_read_print_set_end(main); + } + + funlockfile(main->output.to.stream); + } + } +#endif // _di_fss_payload_read_print_at_ + +#ifndef _di_fss_payload_read_print_at_extended_ + void fss_payload_read_print_at_extended(fss_payload_read_main_t * const main, const f_array_length_t at, const f_fss_delimits_t delimits_object, const f_fss_delimits_t delimits_content, fss_payload_read_data_t * const data) { + + if (at >= data->contents_header.used) { + return; + } + + flockfile(main->output.to.stream); + + if ((data->option & fss_payload_read_data_option_object_d) || (data->option & fss_payload_read_data_option_content_d) && (data->contents_header.array[at].used || (data->option & fss_payload_read_data_option_empty_d))) { + if (data->option & fss_payload_read_data_option_object_d) { + if (data->option & fss_payload_read_data_option_trim_d) { + if ((data->option & fss_payload_read_data_option_raw_d) && data->quotes_object_header.array[at]) { + f_print_character_safely(data->quotes_object_header.array[at] == f_fss_quote_type_single_e ? f_fss_quote_single_s[0] : f_fss_quote_double_s[0], main->output.to.stream); + } + + fl_print_trim_except_dynamic_partial(data->buffer, data->objects_header.array[at], delimits_object, main->output.to.stream); + + if ((data->option & fss_payload_read_data_option_raw_d) && data->quotes_object_header.array[at]) { + f_print_character_safely(data->quotes_object_header.array[at] == f_fss_quote_type_single_e ? f_fss_quote_single_s[0] : f_fss_quote_double_s[0], main->output.to.stream); + } + } + else { + if ((data->option & fss_payload_read_data_option_raw_d) && data->quotes_object_header.array[at]) { + f_print_character_safely(data->quotes_object_header.array[at] == f_fss_quote_type_single_e ? f_fss_quote_single_s[0] : f_fss_quote_double_s[0], main->output.to.stream); + } + + f_print_except_dynamic_partial(data->buffer, data->objects_header.array[at], delimits_object, main->output.to.stream); + + if ((data->option & fss_payload_read_data_option_raw_d) && data->quotes_object_header.array[at]) { + f_print_character_safely(data->quotes_object_header.array[at] == f_fss_quote_type_single_e ? f_fss_quote_single_s[0] : f_fss_quote_double_s[0], main->output.to.stream); + } + } + + if (data->option & fss_payload_read_data_option_content_d) { + fss_payload_read_print_object_end_extended(main); + } + } + + bool content_printed = F_false; + + if ((data->option & fss_payload_read_data_option_content_d) && data->contents_header.array[at].used) { + if (data->option & fss_payload_read_data_option_select_d) { + if (data->select < data->contents_header.array[at].used) { + content_printed = F_true; + + if ((data->option & fss_payload_read_data_option_raw_d) && data->quotes_content_header.array[at].array[data->select]) { + f_print_character_safely(data->quotes_content_header.array[at].array[data->select] == f_fss_quote_type_single_e ? f_fss_quote_single_s[0] : f_fss_quote_double_s[0], main->output.to.stream); + } + + f_print_except_dynamic_partial(data->buffer, data->contents_header.array[at].array[data->select], delimits_content, main->output.to.stream); + + if ((data->option & fss_payload_read_data_option_raw_d) && data->quotes_content_header.array[at].array[data->select]) { + f_print_character_safely(data->quotes_content_header.array[at].array[data->select] == f_fss_quote_type_single_e ? f_fss_quote_single_s[0] : f_fss_quote_double_s[0], main->output.to.stream); + } + } + } + else { + for (f_array_length_t i = 0; i < data->contents_header.array[at].used; ++i) { + + if (data->contents_header.array[at].array[i].start > data->contents_header.array[at].array[i].stop) { + continue; + } + + content_printed = F_true; + + if ((data->option & fss_payload_read_data_option_raw_d) && data->quotes_content_header.array[at].array[i]) { + f_print_character_safely(data->quotes_content_header.array[at].array[i] == f_fss_quote_type_single_e ? f_fss_quote_single_s[0] : f_fss_quote_double_s[0], main->output.to.stream); + } + + f_print_except_dynamic_partial(data->buffer, data->contents_header.array[at].array[i], delimits_content, main->output.to.stream); + + if ((data->option & fss_payload_read_data_option_raw_d) && data->quotes_content_header.array[at].array[i]) { + f_print_character_safely(data->quotes_content_header.array[at].array[i] == f_fss_quote_type_single_e ? f_fss_quote_single_s[0] : f_fss_quote_double_s[0], main->output.to.stream); + } + + if (i + 1 < data->contents_header.array[at].used && data->contents_header.array[at].array[i + 1].start <= data->contents_header.array[at].array[i + 1].stop) { + fss_payload_read_print_content_end_extended(main); + } + } // for + } + } + + if ((data->option & fss_payload_read_data_option_object_d) || (data->option & fss_payload_read_data_option_content_d) && (content_printed || (data->option & fss_payload_read_data_option_empty_d))) { + fss_payload_read_print_set_end_extended(main); + } + + funlockfile(main->output.to.stream); + } + } +#endif // _di_fss_payload_read_print_at_extended_ + +#ifndef _di_fss_payload_read_print_at_object_ + void fss_payload_read_print_at_object(fss_payload_read_main_t * const main, fss_payload_read_data_t * const data, const f_array_length_t at, const f_fss_delimits_t delimits_object) { + + if (at >= data->objects.used) { + return; + } + + if (data->option & fss_payload_read_data_option_trim_d) { + fl_print_trim_except_dynamic_partial(data->buffer, data->objects.array[at], delimits_object, main->output.to.stream); + } + else { + f_print_except_dynamic_partial(data->buffer, data->objects.array[at], delimits_object, main->output.to.stream); + } + + fss_payload_read_print_object_end(main); + } +#endif // _di_fss_payload_read_print_at_object_ + +#ifndef _di_fss_payload_read_print_at_total_exteded_ + f_status_t fss_payload_read_print_at_total_extended(fss_payload_read_main_t * const main, const f_array_length_t at, fss_payload_read_data_t *data) { + + if (data->option & fss_payload_read_data_option_select_d) { + if (data->option & fss_payload_read_data_option_object_d) { + flockfile(main->output.to.stream); + + fss_payload_read_print_one(main); + + funlockfile(main->output.to.stream); + + return F_success; + } + + if (data->select < data->contents_header.array[at].used) { + if (data->contents_header.array[at].array[data->select].start <= data->contents_header.array[at].array[data->select].stop || (data->option & fss_payload_read_data_option_empty_d)) { + flockfile(main->output.to.stream); + + fss_payload_read_print_one(main); + + funlockfile(main->output.to.stream); + + return F_success; + } + } + } + else if ((data->option & fss_payload_read_data_option_object_d) || (data->option & fss_payload_read_data_option_empty_d)) { + flockfile(main->output.to.stream); + + fss_payload_read_print_one(main); + + funlockfile(main->output.to.stream); + + return F_success; + } + else if (data->contents_header.array[at].used) { + for (f_array_length_t j = 0; j < data->contents_header.array[at].used; ++j) { + + if (data->contents_header.array[at].array[j].start <= data->contents_header.array[at].array[j].stop) { + flockfile(main->output.to.stream); + + fss_payload_read_print_one(main); + + funlockfile(main->output.to.stream); + + return F_success; + } + } // for + } + + return F_none; + } +#endif // _di_fss_payload_read_print_at_total_extended_ + +#ifndef _di_fss_payload_read_print_content_end_extended_ + void fss_payload_read_print_content_end_extended(fss_payload_read_main_t * const main) { + + if (main->parameters[fss_payload_read_parameter_pipe_e].result == f_console_result_found_e) { + f_print_character(fss_payload_read_pipe_content_start_s, main->output.to.stream); + } + else { + f_print_character(F_fss_space_s[0], main->output.to.stream); + } + } +#endif // _di_fss_payload_read_print_content_end_extended_ + +#ifndef _di_fss_payload_read_print_content_ignore_ + void fss_payload_read_print_content_ignore(fss_payload_read_main_t * const main) { + + if (main->parameters[fss_payload_read_parameter_pipe_e].result == f_console_result_found_e) { + f_print_character(fss_payload_read_pipe_content_ignore_s, main->output.to.stream); + } + } +#endif // _di_fss_payload_read_print_content_ignore_ + +#ifndef _di_fss_payload_read_print_object_end_ + void fss_payload_read_print_object_end(fss_payload_read_main_t * const main) { + + if (main->parameters[fss_payload_read_parameter_pipe_e].result == f_console_result_found_e) { + f_print_character(fss_payload_read_pipe_content_start_s, main->output.to.stream); + } + else { + if (main->parameters[fss_payload_read_parameter_content_e].result == f_console_result_found_e) { + f_print_character(f_fss_basic_list_open_s[0], main->output.to.stream); + f_print_character(f_fss_basic_list_open_end_s[0], main->output.to.stream); + } + else { + f_print_character(f_fss_eol_s[0], main->output.to.stream); + } + } + } +#endif // _di_fss_payload_read_print_object_end_ + +#ifndef _di_fss_payload_read_print_object_end_extended_ + void fss_payload_read_print_object_end_extended(fss_payload_read_main_t * const main) { + + if (main->parameters[fss_payload_read_parameter_pipe_e].result == f_console_result_found_e) { + f_print_character(fss_payload_read_pipe_content_end_s, main->output.to.stream); + } + else { + f_print_character(F_fss_space_s[0], main->output.to.stream); + } + } +#endif // _di_fss_payload_read_print_object_end_extended_ + +#ifndef _di_fss_payload_read_print_set_end_ + void fss_payload_read_print_set_end(fss_payload_read_main_t * const main) { + + if (main->parameters[fss_payload_read_parameter_pipe_e].result == f_console_result_found_e) { + f_print_character(fss_payload_read_pipe_content_end_s, main->output.to.stream); + } + } +#endif // _di_fss_payload_read_print_set_end_ + +#ifndef _di_fss_payload_read_print_set_end_extended_ + void fss_payload_read_print_set_end_extended(fss_payload_read_main_t * const main) { + + if (main->parameters[fss_payload_read_parameter_pipe_e].result == f_console_result_found_e) { + f_print_character(fss_payload_read_pipe_content_end_s, main->output.to.stream); + } + else { + f_print_character(f_fss_eol_s[0], main->output.to.stream); + } + } +#endif // _di_fss_payload_read_print_set_end_extended_ + +#ifndef _di_fss_payload_read_print_one_ + void fss_payload_read_print_one(fss_payload_read_main_t * const main) { + + f_print_character(f_string_ascii_1_s[0], main->output.to.stream); + f_print_character(f_string_eol_s[0], main->output.to.stream); + } +#endif // _di_fss_payload_read_print_one_ + +#ifndef _di_fss_payload_read_print_zero_ + void fss_payload_read_print_zero(fss_payload_read_main_t * const main) { + + f_print_character(f_string_ascii_0_s[0], main->output.to.stream); + f_print_character(f_string_eol_s[0], main->output.to.stream); + } +#endif // _di_fss_payload_read_print_zero_ + +#ifndef _di_fss_payload_read_process_ + f_status_t fss_payload_read_process(fss_payload_read_main_t * const main, const f_console_arguments_t *arguments, fss_payload_read_data_t *data) { + + f_status_t status = fss_payload_read_process_option(main, arguments, data); + if (F_status_is_error(status)) return status; + + // This standard does not support multiple content groups, except for "headers" FSS-0001 Extended at depth 1. + if (!(data->option & fss_payload_read_data_option_extended_d)) { + if ((data->option & fss_payload_read_data_option_select_d) && data->select) { + if (main->parameters[fss_payload_read_parameter_total_e].result == f_console_result_found_e) { + flockfile(main->output.to.stream); + + fss_payload_read_print_zero(main); + + funlockfile(main->output.to.stream); + } + + return F_none; + } + } + + status = fss_payload_read_load(main, data); + if (F_status_is_error(status)) return status; + + bool names[data->objects.used]; + + status = fss_payload_read_process_name(data, names); + if (F_status_is_error(status)) return status; + + if (data->option & fss_payload_read_data_option_extended_d) { + + // For "headers" FSS-0001 Extended, only operate if the "header" name is true. + for (f_array_length_t i = 0; i < data->objects.used; ++i) { + + if (fl_string_dynamic_partial_compare_string(F_fss_string_header_s, data->buffer, F_fss_string_header_s_length, data->objects.array[i]) == F_equal_to) { + if (names[i]) break; + + if (main->parameters[fss_payload_read_parameter_total_e].result == f_console_result_found_e) { + flockfile(main->output.to.stream); + + fss_payload_read_print_zero(main); + + funlockfile(main->output.to.stream); + } + + return F_none; + } + } // for + + bool names_header[data->objects_header.used]; + + status = fss_payload_read_process_name_extended(data, names_header); + if (F_status_is_error(status)) return status; + + if (data->depths.array[data->depths.used - 1].index_at) { + return fss_payload_read_process_at_extended(main, data, names_header); + } + + if (data->option & fss_payload_read_data_option_columns_d) { + return fss_payload_read_process_columns_extended(main, data, names_header); + } + + if (data->option & fss_payload_read_data_option_total_d) { + return fss_payload_read_process_total_extended(main, data, names_header); + } + + if (data->option & fss_payload_read_data_option_line_d) { + return fss_payload_read_process_line_extended(main, data, names_header); + } + + f_array_lengths_t except_none = f_array_lengths_t_initialize; + f_array_lengths_t *delimits_object = fss_payload_read_delimit_object_is(0, data) ? &data->delimits_object_header : &except_none; + f_array_lengths_t *delimits_content = fss_payload_read_delimit_content_is((data->option & fss_payload_read_data_option_select_d) ? data->select : 0, data) ? &data->delimits_content_header : &except_none; + + if (data->option & fss_payload_read_data_option_raw_d) { + delimits_object = &except_none; + delimits_content = &except_none; + } + + for (f_array_length_t i = 0; i < data->contents.used; ++i) { + + if (!names_header[i]) continue; + + fss_payload_read_print_at_extended(main, i, *delimits_object, *delimits_content, data); + } // for + + return F_none; + } + + if (data->depths.array[0].index_at) { + return fss_payload_read_process_at(main, data, names); + } + + if (data->option & fss_payload_read_data_option_columns_d) { + return fss_payload_read_process_columns(main, data, names); + } + + if (data->option & fss_payload_read_data_option_total_d) { + return fss_payload_read_process_total(main, data, names); + } + + if (data->option & fss_payload_read_data_option_line_d) { + return fss_payload_read_process_line(main, data, names); + } + + f_array_lengths_t except_none = f_array_lengths_t_initialize; + f_array_lengths_t *delimits_object = fss_payload_read_delimit_object_is(0, data) ? &data->delimits_object : &except_none; + f_array_lengths_t *delimits_content = fss_payload_read_delimit_content_is(0, data) ? &data->delimits_content : &except_none; + uint16_t signal_check = 0; + bool is_payload = F_false; + + if (data->option & fss_payload_read_data_option_raw_d) { + delimits_object = &except_none; + delimits_content = &except_none; + } + + for (f_array_length_t i = 0; i < data->contents.used; ++i) { + + if (!names[i]) continue; + + if (!((++signal_check) % fss_payload_read_signal_check_d)) { + if (fss_payload_read_signal_received(main)) { + return F_status_set_error(F_interrupt); + } + + signal_check = 0; + } + + is_payload = fl_string_dynamic_partial_compare_string(F_fss_string_payload_s, data->buffer, F_fss_string_payload_s_length, data->objects.array[i]) == F_equal_to; + + fss_payload_read_print_at(main, is_payload, i, *delimits_object, *delimits_content, data); + } // for + + return F_none; + } +#endif // _di_fss_payload_read_process_ + +#ifndef _di_fss_payload_read_process_at_ + f_status_t fss_payload_read_process_at(fss_payload_read_main_t * const main, fss_payload_read_data_t *data, bool names[]) { + + if (data->depths.array[0].value_at >= data->objects.used) { + if (data->option & (fss_payload_read_data_option_columns_d | fss_payload_read_data_option_total_d)) { + flockfile(main->output.to.stream); + + fss_payload_read_print_zero(main); + + funlockfile(main->output.to.stream); + } + + return F_none; + } + + f_array_lengths_t except_none = f_array_lengths_t_initialize; + f_array_lengths_t *delimits_object = fss_payload_read_delimit_object_is(0, data) ? &data->delimits_object : &except_none; + f_array_lengths_t *delimits_content = fss_payload_read_delimit_content_is(0, data) ? &data->delimits_content : &except_none; + + if (data->option & fss_payload_read_data_option_raw_d) { + delimits_object = &except_none; + delimits_content = &except_none; + } + + f_array_length_t at = 0; + f_status_t status = F_none; + uint16_t signal_check = 0; + bool is_payload = F_false; + + for (f_array_length_t i = 0; i < data->objects.used; ++i) { + + if (!names[i]) continue; + + if (!((++signal_check) % fss_payload_read_signal_check_d)) { + if (fss_payload_read_signal_received(main)) { + return F_status_set_error(F_interrupt); + } + + signal_check = 0; + } + + if (at == data->depths.array[0].value_at) { + if (data->option & fss_payload_read_data_option_line_d) { + f_array_length_t line = 0; + + status = fss_payload_read_process_at_line(main, i, *delimits_object, *delimits_content, data, &line); + if (status == F_success) return F_none; + } + else if (data->option & fss_payload_read_data_option_columns_d) { + fll_print_format("%ul%c", main->output.to.stream, data->contents.array[i].used, f_string_eol_s[0]); + } + else if (data->option & fss_payload_read_data_option_total_d) { + flockfile(main->output.to.stream); + + if (data->contents.array[i].used) { + fss_payload_read_print_one(main); + } + else { + fss_payload_read_print_zero(main); + } + + funlockfile(main->output.to.stream); + } + else { + is_payload = fl_string_dynamic_partial_compare_string(F_fss_string_payload_s, data->buffer, F_fss_string_payload_s_length, data->objects.array[i]) == F_equal_to; + + fss_payload_read_print_at(main, is_payload, i, *delimits_object, *delimits_content, data); + } + + return F_none; + } + + ++at; + } // for + + if (data->option & fss_payload_read_data_option_total_d) { + flockfile(main->output.to.stream); + + fss_payload_read_print_zero(main); + + funlockfile(main->output.to.stream); + } + + return F_none; + } +#endif // _di_fss_payload_read_process_at_ + +#ifndef _di_fss_payload_read_process_at_extended_ + f_status_t fss_payload_read_process_at_extended(fss_payload_read_main_t * const main, fss_payload_read_data_t *data, bool names[]) { + + if (data->depths.array[data->depths.used - 1].value_at >= data->objects_header.used) { + if (data->option & (fss_payload_read_data_option_columns_d | fss_payload_read_data_option_total_d)) { + flockfile(main->output.to.stream); + + fss_payload_read_print_zero(main); + + funlockfile(main->output.to.stream); + } + + return F_none; + } + + // This standard only has one line per Content; therefore, any line value greater than 0 equates to no line to print. + if (data->option & fss_payload_read_data_option_line_d) { + if (data->line) { + if (data->option & fss_payload_read_data_option_total_d) { + flockfile(main->output.to.stream); + + fss_payload_read_print_zero(main); + + funlockfile(main->output.to.stream); + } + + return F_none; + } + } + + f_array_lengths_t except_none = f_array_lengths_t_initialize; + f_array_lengths_t *delimits_object = fss_payload_read_delimit_object_is(0, data) ? &data->delimits_object_header : &except_none; + f_array_lengths_t *delimits_content = fss_payload_read_delimit_content_is((data->option & fss_payload_read_data_option_select_d) ? data->select : 0, data) ? &data->delimits_content_header : &except_none; + + if (data->option & fss_payload_read_data_option_raw_d) { + delimits_object = &except_none; + delimits_content = &except_none; + } + + f_array_length_t at = 0; + + for (f_array_length_t i = 0; i < data->objects_header.used; ++i) { + + if (!names[i]) continue; + + if (at == data->depths.array[data->depths.used - 1].value_at) { + if (data->option & fss_payload_read_data_option_line_d) { + + // This standard only supports one line per Object so when using "--at", the only valid line is line 0. + if (data->line) break; + + if (data->option & fss_payload_read_data_option_total_d) { + if (fss_payload_read_print_at_total_extended(main, i, data) == F_none) { + break; + } + } + else { + if ((data->option & fss_payload_read_data_option_raw_d) && data->quotes_object_header.array[at]) { + f_print_character_safely(data->quotes_object_header.array[at] == f_fss_quote_type_single_e ? f_fss_quote_single_s[0] : f_fss_quote_double_s[0], main->output.to.stream); + } + + fss_payload_read_print_at_extended(main, i, *delimits_object, *delimits_content, data); + + if ((data->option & fss_payload_read_data_option_raw_d) && data->quotes_object_header.array[at]) { + f_print_character_safely(data->quotes_object_header.array[at] == f_fss_quote_type_single_e ? f_fss_quote_single_s[0] : f_fss_quote_double_s[0], main->output.to.stream); + } + } + } + else if (data->option & fss_payload_read_data_option_columns_d) { + fll_print_format("%ul%c", main->output.to.stream, data->contents_header.array[i].used, f_string_eol_s[0]); + } + else if (data->option & fss_payload_read_data_option_total_d) { + if (fss_payload_read_print_at_total_extended(main, i, data) == F_none) { + break; + } + } + else { + if ((data->option & fss_payload_read_data_option_raw_d) && data->quotes_content_header.array[at].array[i]) { + f_print_character_safely(data->quotes_content_header.array[at].array[i] == f_fss_quote_type_single_e ? f_fss_quote_single_s[0] : f_fss_quote_double_s[0], main->output.to.stream); + } + + fss_payload_read_print_at_extended(main, i, *delimits_object, *delimits_content, data); + + if ((data->option & fss_payload_read_data_option_raw_d) && data->quotes_content_header.array[at].array[i]) { + f_print_character_safely(data->quotes_content_header.array[at].array[i] == f_fss_quote_type_single_e ? f_fss_quote_single_s[0] : f_fss_quote_double_s[0], main->output.to.stream); + } + } + + return F_none; + } + + ++at; + } // for + + if (data->option & fss_payload_read_data_option_total_d) { + flockfile(main->output.to.stream); + + fss_payload_read_print_zero(main); + + funlockfile(main->output.to.stream); + } + + return F_none; + } +#endif // _di_fss_payload_read_process_at_extended_ + +#ifndef _di_fss_payload_read_process_at_line_ + f_status_t fss_payload_read_process_at_line(fss_payload_read_main_t * const main, const f_array_length_t at, const f_array_lengths_t delimits_object, const f_array_lengths_t delimits_content, fss_payload_read_data_t *data, f_array_length_t *line) { + + if (data->option & fss_payload_read_data_option_object_d) { + if (*line == data->line) { + flockfile(main->output.to.stream); + + if (data->option & fss_payload_read_data_option_total_d) { + fss_payload_read_print_one(main); + } + else { + fss_payload_read_print_at_object(main, data, at, delimits_object); + } + + funlockfile(main->output.to.stream); + + return F_success; + } + + ++(*line); + } + + // There is only a single Content column for this standard. + if (data->option & fss_payload_read_data_option_content_d) { + if (!data->contents.array[at].used) { + return F_none; + } + + f_string_range_t range = f_string_range_t_initialize; + f_array_length_t i = 0; + uint16_t signal_check = 0; + + range.start = data->contents.array[at].array[0].start; + range.stop = data->contents.array[at].array[0].stop; + + // This content has no data, do not even check "include empty" because it cannot be counted as a line. + if (range.start > range.stop) { + return F_none; + } + + for (i = range.start; i <= range.stop; ++i) { + + if (!((++signal_check) % fss_payload_read_signal_check_d)) { + if (fss_payload_read_signal_received(main)) { + return F_status_set_error(F_interrupt); + } + + signal_check = 0; + } + + if (data->buffer.string[i] == f_string_eol_s[0]) { + if (*line == data->line) { + range.stop = i; + + flockfile(main->output.to.stream); + + if (data->option & fss_payload_read_data_option_total_d) { + fss_payload_read_print_one(main); + } + else { + f_print_except_in_dynamic_partial(data->buffer, range, delimits_content, data->comments, main->output.to.stream); + } + + funlockfile(main->output.to.stream); + + return F_success; + } + + range.start = i + 1; + + if (i <= range.stop) { + ++(*line); + } + } + } // for + + // If Content does not end with a newline, it still must be treated as the last line. + if (data->buffer.string[range.stop] != f_string_eol_s[0]) { + ++(*line); + + if (*line == data->line) { + flockfile(main->output.to.stream); + + if (data->option & fss_payload_read_data_option_total_d) { + fss_payload_read_print_one(main); + } + else { + range.stop = data->contents.array[at].array[0].stop; + + f_print_except_in_dynamic_partial(data->buffer, range, delimits_content, data->comments, main->output.to.stream); + f_print_character(f_string_eol_s[0], main->output.to.stream); + } + + funlockfile(main->output.to.stream); + + return F_success; + } + } + } + + return F_none; + } +#endif // _di_fss_payload_read_process_at_line_ + +#ifndef _di_fss_payload_read_process_columns_ + f_status_t fss_payload_read_process_columns(fss_payload_read_main_t * const main, fss_payload_read_data_t *data, bool names[]) { + + if (!(data->option & fss_payload_read_data_option_content_d)) { + flockfile(main->output.to.stream); + + fss_payload_read_print_zero(main); + + funlockfile(main->output.to.stream); + + return F_none; + } + + f_array_length_t max = 0; + uint16_t signal_check = 0; + + for (f_array_length_t at = 0; at < data->contents.used; ++at) { + + if (!names[at]) continue; + + if (!((++signal_check) % fss_payload_read_signal_check_d)) { + if (fss_payload_read_signal_received(main)) { + return F_status_set_error(F_interrupt); + } + + signal_check = 0; + } + + if (data->contents.array[at].used > max) { + max = data->contents.array[at].used; + } + } // for + + fll_print_format("%ul%c", main->output.to.stream, max, f_string_eol_s[0]); + + return F_none; + } +#endif // _di_fss_payload_read_process_columns_ + +#ifndef _di_fss_payload_read_process_columns_extended_ + f_status_t fss_payload_read_process_columns_extended(fss_payload_read_main_t * const main, fss_payload_read_data_t *data, bool names[]) { + + if (!(data->option & fss_payload_read_data_option_content_d)) { + flockfile(main->output.to.stream); + + fss_payload_read_print_zero(main); + + funlockfile(main->output.to.stream); + + return F_none; + } + + f_array_length_t max = 0; + + for (f_array_length_t at = 0; at < data->contents_header.used; ++at) { + + if (!names[at]) continue; + + if (data->contents_header.array[at].used > max) { + max = data->contents_header.array[at].used; + } + } // for + + fll_print_format("%ul%c", main->output.to.stream, max, f_string_eol_s[0]); + + return F_none; + } +#endif // _di_fss_payload_read_process_columns_extended_ + +#ifndef _di_fss_payload_read_process_line_ + f_status_t fss_payload_read_process_line(fss_payload_read_main_t * const main, fss_payload_read_data_t *data, bool names[]) { + + f_array_lengths_t except_none = f_array_lengths_t_initialize; + f_array_lengths_t *delimits_object = fss_payload_read_delimit_object_is(0, data) ? &data->delimits_object : &except_none; + f_array_lengths_t *delimits_content = fss_payload_read_delimit_content_is(0, data) ? &data->delimits_content : &except_none; + + if (data->option & fss_payload_read_data_option_raw_d) { + delimits_object = &except_none; + delimits_content = &except_none; + } + + f_array_length_t line = 0; + f_status_t status = F_none; + uint16_t signal_check = 0; + + for (f_array_length_t i = 0; i < data->contents.used; ++i) { + + if (!names[i]) continue; + + if (!((++signal_check) % fss_payload_read_signal_check_d)) { + if (fss_payload_read_signal_received(main)) { + return F_status_set_error(F_interrupt); + } + + signal_check = 0; + } + + status = fss_payload_read_process_at_line(main, i, *delimits_object, *delimits_content, data, &line); + if (status == F_success) break; + } // for + + return F_none; + } +#endif // _di_fss_payload_read_process_line_ + +#ifndef _di_fss_payload_read_process_line_extended_ + f_status_t fss_payload_read_process_line_extended(fss_payload_read_main_t * const main, fss_payload_read_data_t *data, bool names[]) { + + f_array_lengths_t except_none = f_array_lengths_t_initialize; + f_array_lengths_t *delimits_object = fss_payload_read_delimit_object_is(0, data) ? &data->delimits_object_header : &except_none; + f_array_lengths_t *delimits_content = fss_payload_read_delimit_content_is((data->option & fss_payload_read_data_option_select_d) ? data->select : 0, data) ? &data->delimits_content_header : &except_none; + + if (data->option & fss_payload_read_data_option_raw_d) { + delimits_object = &except_none; + delimits_content = &except_none; + } + + f_array_length_t line = 0; + + for (f_array_length_t i = 0; i < data->contents_header.used; ++i) { + + if (!names[i]) continue; + + if (!(data->option & fss_payload_read_data_option_object_d) && (data->option & fss_payload_read_data_option_content_d)) { + if (!data->contents_header.array[i].used) { + if (data->option & fss_payload_read_data_option_empty_d) { + if (line == data->line) { + flockfile(main->output.to.stream); + + fss_payload_read_print_set_end_extended(main); + + funlockfile(main->output.to.stream); + + break; + } + + ++line; + } + + continue; + } + } + + if (line == data->line) { + fss_payload_read_print_at_extended(main, i, *delimits_object, *delimits_content, data); + + break; + } + + ++line; + } // for + + return F_none; + } +#endif // _di_fss_payload_read_process_line_extended_ + +#ifndef _di_fss_payload_read_process_name_ + f_status_t fss_payload_read_process_name(fss_payload_read_data_t *data, bool names[]) { + + f_array_lengths_t except_none = f_array_lengths_t_initialize; + + if (data->depths.array[0].index_name) { + f_array_length_t i = 0; + + memset(names, F_false, sizeof(bool) * data->objects.used); + + // This standard should always tread selected names as trimmed. + for (i = 0; i < data->objects.used; ++i) { + + if (fl_string_dynamic_partial_compare_except_trim_dynamic(data->depths.array[0].value_name, data->buffer, data->objects.array[i], except_none, data->delimits_object) == F_equal_to) { + names[i] = F_true; + } + } // for + } + else { + memset(names, F_true, sizeof(bool) * data->objects.used); + } + + return F_none; + } +#endif // _di_fss_payload_read_process_name_ + +#ifndef _di_fss_payload_read_process_name_extended_ + f_status_t fss_payload_read_process_name_extended(fss_payload_read_data_t *data, bool names[]) { + + f_array_lengths_t except_none = f_array_lengths_t_initialize; + + if (data->depths.array[data->depths.used - 1].index_name) { + f_array_length_t i = 0; + + memset(names, F_false, sizeof(bool) * data->objects_header.used); + + if (data->option & fss_payload_read_data_option_trim_d) { + for (i = 0; i < data->objects_header.used; ++i) { + + if (fl_string_dynamic_partial_compare_except_trim_dynamic(data->depths.array[data->depths.used - 1].value_name, data->buffer, data->objects_header.array[i], except_none, data->delimits_object_header) == F_equal_to) { + names[i] = F_true; + } + } // for + } + else { + for (i = 0; i < data->objects_header.used; ++i) { + + if (fl_string_dynamic_partial_compare_except_dynamic(data->depths.array[data->depths.used - 1].value_name, data->buffer, data->objects_header.array[i], except_none, data->delimits_content_header) == F_equal_to) { + names[i] = F_true; + } + } // for + } + } + else { + memset(names, F_true, sizeof(bool) * data->objects_header.used); + } + + return F_none; + } +#endif // _di_fss_payload_read_process_name_extended_ + +#ifndef _di_fss_payload_read_process_option_ + f_status_t fss_payload_read_process_option(fss_payload_read_main_t * const main, const f_console_arguments_t *arguments, fss_payload_read_data_t *data) { + + f_status_t status = F_none; + + if (main->parameters[fss_payload_read_parameter_at_e].result == f_console_result_additional_e) { + data->option |= fss_payload_read_data_option_at_d; + } + + if (main->parameters[fss_payload_read_parameter_columns_e].result == f_console_result_found_e) { + data->option |= fss_payload_read_data_option_columns_d; + } + + if (main->parameters[fss_payload_read_parameter_content_e].result == f_console_result_found_e) { + data->option |= fss_payload_read_data_option_content_d; + } + + if (main->parameters[fss_payload_read_parameter_empty_e].result == f_console_result_found_e) { + data->option |= fss_payload_read_data_option_empty_d; + } + + if (main->parameters[fss_payload_read_parameter_line_e].result == f_console_result_additional_e) { + data->option |= fss_payload_read_data_option_line_d; + + status = fss_payload_read_load_number(main, fss_payload_read_parameter_line_e, fss_payload_read_long_line_s, arguments, &data->line); + if (F_status_is_error(status)) return status; + } + + if (main->parameters[fss_payload_read_parameter_name_e].result == f_console_result_additional_e) { + data->option |= fss_payload_read_data_option_name_d; + } + + if (main->parameters[fss_payload_read_parameter_object_e].result == f_console_result_found_e) { + data->option |= fss_payload_read_data_option_object_d; + } + + if (main->parameters[fss_payload_read_parameter_raw_e].result == f_console_result_found_e) { + data->option |= fss_payload_read_data_option_raw_d; + } + + if (main->parameters[fss_payload_read_parameter_select_e].result == f_console_result_additional_e) { + data->option |= fss_payload_read_data_option_select_d; + + status = fss_payload_read_load_number(main, fss_payload_read_parameter_select_e, fss_payload_read_long_select_s, arguments, &data->select); + if (F_status_is_error(status)) return status; + } + + if (main->parameters[fss_payload_read_parameter_total_e].result == f_console_result_found_e) { + data->option |= fss_payload_read_data_option_total_d; + } + + if (main->parameters[fss_payload_read_parameter_trim_e].result == f_console_result_found_e) { + data->option |= fss_payload_read_data_option_trim_d; + } + + // Default to content if neither Object nor Content is explicitly requested. + if (!(data->option & (fss_payload_read_data_option_content_d | fss_payload_read_data_option_object_d))) { + data->option |= fss_payload_read_data_option_content_d; + } + + return F_none; + } +#endif // _di_fss_payload_read_process_option_ + +#ifndef _di_fss_payload_read_process_total_ + f_status_t fss_payload_read_process_total(fss_payload_read_main_t * const main, fss_payload_read_data_t *data, bool names[]) { + + f_array_length_t total = 0; + f_string_range_t range = f_string_range_t_initialize; + f_array_length_t i = 0; + uint16_t signal_check = 0; + + for (f_array_length_t at = 0; at < data->contents.used; ++at) { + + if (!names[at]) continue; + + if (!((++signal_check) % fss_payload_read_signal_check_d)) { + if (fss_payload_read_signal_received(main)) { + return F_status_set_error(F_interrupt); + } + + signal_check = 0; + } + + if (data->option & fss_payload_read_data_option_object_d) { + ++total; + } + + // There is only a single Content column for this standard. + if (data->option & fss_payload_read_data_option_content_d) { + + if (!data->contents.array[at].used) continue; + + range.start = data->contents.array[at].array[0].start; + range.stop = data->contents.array[at].array[0].stop; + + // This content has no data, do not even check "include empty" because it cannot be counted as a line. + if (range.start > range.stop) { + continue; + } + + for (i = range.start; i <= range.stop; ++i) { + + if (data->buffer.string[i] == f_string_eol_s[0]) { + range.start = i + 1; + + if (i <= range.stop) { + ++total; + } + } + } // for + + // If Content does not end with a newline, it still must be treated as the last line. + if (data->buffer.string[range.stop] != f_string_eol_s[0]) { + ++total; + } + } + } // for + + flockfile(main->output.to.stream); + + if (data->option & fss_payload_read_data_option_line_d) { + if (data->line < total) { + fss_payload_read_print_one(main); + } + else { + fss_payload_read_print_zero(main); + } + } + else { + fl_print_format("%ul%c", main->output.to.stream, total, f_string_eol_s[0]); + } + + funlockfile(main->output.to.stream); + + return F_none; + } +#endif // _di_fss_payload_read_process_total_ + +#ifndef _di_fss_payload_read_process_total_extended_ + f_status_t fss_payload_read_process_total_extended(fss_payload_read_main_t * const main, fss_payload_read_data_t *data, bool names[]) { + + f_array_length_t total = 0; + + // This standard only has one Content per line, however it has multiple Contents within that line. + if ((data->option & fss_payload_read_data_option_object_d) || (data->option & fss_payload_read_data_option_content_d) && (data->option & fss_payload_read_data_option_empty_d)) { + for (f_array_length_t i = 0; i < data->objects_header.used; ++i) { + + if (!names[i]) continue; + + ++total; + } // for + } + else { + f_array_length_t i = 0; + f_array_length_t j = 0; + + for (; i < data->contents_header.used; ++i) { + + if (!names[i]) continue; + if (!data->contents_header.array[i].used) continue; + + if ((data->option & fss_payload_read_data_option_select_d) && data->contents_header.array[i].used <= data->select) { + continue; + } + + for (j = 0; j < data->contents_header.array[i].used; ++j) { + + if (data->contents_header.array[i].array[j].start <= data->contents_header.array[i].array[j].stop) { + if (data->option & fss_payload_read_data_option_select_d) { + if (j == data->select) { + ++total; + + break; + } + } + else { + ++total; + + break; + } + } + } // for + } // for + } + + flockfile(main->output.to.stream); + + if (data->option & fss_payload_read_data_option_line_d) { + if (data->line < total) { + fss_payload_read_print_one(main); + } + else { + fss_payload_read_print_zero(main); + } + } + else { + fl_print_format("%ul%c", main->output.to.stream, total, f_string_eol_s[0]); + } + + funlockfile(main->output.to.stream); + + return F_none; + } +#endif // _di_fss_payload_read_process_total_extended_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_3/fss_payload_read/c/private-fss_payload_read.h b/level_3/fss_payload_read/c/private-fss_payload_read.h new file mode 100644 index 0000000..5ff982a --- /dev/null +++ b/level_3/fss_payload_read/c/private-fss_payload_read.h @@ -0,0 +1,571 @@ +/** + * FLL - Level 3 + * + * Project: FSS + * API Version: 0.5 + * Licenses: lgpl-2.1-or-later + */ +#ifndef _PRIVATE_fss_payload_read_h +#define _PRIVATE_fss_payload_read_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Determine if the given depth is to be delimited or not for Content. + * + * @param depth + * The depth to check. + * @param data + * The program data. + * + * @return + * F_true if to apply delimits. + * F_false if to not apply delimits. + */ +#ifndef _di_fss_payload_read_delimit_content_is_ + extern f_status_t fss_payload_read_delimit_content_is(const f_array_length_t depth, fss_payload_read_data_t * const data) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_delimit_content_is_ + +/** + * Determine if the given depth is to be delimited or not for an Object. + * + * @param depth + * The depth to check. + * @param data + * The program data. + * + * @return + * F_true if to apply delimits. + * F_false if to not apply delimits. + */ +#ifndef _di_fss_payload_read_delimit_object_is_ + extern f_status_t fss_payload_read_delimit_object_is(const f_array_length_t depth, fss_payload_read_data_t * const data) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_delimit_object_is_ + +/** + * 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 main + * The main program data. + * @param arguments + * The parameters passed to the process. + * @param data + * The program data. + * + * @return + * F_none on success. + * + * F_interrupt (with error bit) on receiving a process signal, such as an interrupt signal. + * + * Errors (with error bit) from: f_string_append(). + * Errors (with error bit) from: fl_string_rip(). + * Errors (with error bit) from: fl_conversion_string_to_number_unsigned(). + * + * Errors (with error bit) from: fss_payload_read_depths_resize(). + * + * @see f_string_append() + * @see fl_string_rip() + * @see fl_conversion_string_to_number_unsigned() + * + * @see fss_payload_read_depths_resize() + */ +#ifndef _di_fss_payload_read_depth_process_ + extern f_status_t fss_payload_read_depth_process(fss_payload_read_main_t * const main, const f_console_arguments_t *arguments, fss_payload_read_data_t *data) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_depth_process_ + +/** + * Get the name of the file the given position represents within the buffer. + * + * @param at + * The position within the buffer. + * @param files + * The representation of files and their respective ranges within the buffer. + * + * @return + * A string with the name when found. + * NULL is returned if the range represents the STDIN pipe. + * + * On failure to identify, an empty string is returned. + */ +#ifndef _di_fss_payload_read_file_identify_ + extern f_string_t fss_payload_read_file_identify(const f_array_length_t at, const fss_payload_read_files_t files) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_file_identify_ + +/** + * Process the buffer, loading the FSS data. + * + * This will print an error message on error. + * + * @param main + * The main program data. + * @param data + * The program data. + * + * @return + * F_none on success. + * + * F_data_not_stop (with warning bit) on no valid FSS data found and reached stopping point. + * F_data_not_eos (with warning bit) on no valid FSS data found and reached end of string. + * + * Errors (with error bit) from: fll_fss_payload_read() + * + * @see fll_fss_payload_read() + * + * @see fss_payload_read_process_option() + */ +#ifndef _di_fss_payload_read_load_ + extern f_status_t fss_payload_read_load(fss_payload_read_main_t * const main, fss_payload_read_data_t *data) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_load_ + +/** + * Load a given number parameter. + * + * This will print an error message on error. + * + * @param main + * The main program data. + * @param parameter + * An ID representing the parameter. + * @param name + * The parameter name to print on error. + * @param arguments + * The console arguments passed to the program. + * @param number + * The location to store the loaded number. + * + * @return + * F_true on success and the parameter was found (and is valid). + * F_false on success and the parameter was not found. + * + * Errors (with error bit) from: fl_conversion_string_to_number_unsigned(). + * + * @see fl_conversion_string_to_number_unsigned() + * + * @see fss_payload_read_depths_resize() + */ +#ifndef _di_fss_payload_read_load_number_ + extern f_status_t fss_payload_read_load_number(fss_payload_read_main_t * const main, const f_array_length_t parameter, const f_string_t name, const f_console_arguments_t *arguments, f_number_unsigned_t *number) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_load_number_ + +/** + * Print the Object and Content at the given position. + * + * Only what is requested to print (Object, Content, both, or neither) will be printed, if there is something to print. + * + * @param main + * The main program data. + * @param is_payload + * If TRUE, then this is associated with a "payload" Object. + * @param at + * The index in the Objects and Contents to print. + * @param delimits_object + * The delimits to be applied to an Object. + * @param delimits_content + * The delimits to be applied to Content. + * @param data + * The program data. + */ +#ifndef _di_fss_payload_read_print_at_ + extern void fss_payload_read_print_at(fss_payload_read_main_t * const main, const bool is_payload, const f_array_length_t at, const f_fss_delimits_t delimits_object, const f_fss_delimits_t delimits_content, fss_payload_read_data_t * const data) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_print_at_ + +/** + * Print the Object and Content at the given position for the FSS-0001 Extended Content at depth 1. + * + * Only what is requested to print (Object, Content, both, or neither) will be printed, if there is something to print. + * + * @param main + * The main program data. + * @param at + * The index in the Objects and Contents to print. + * @param delimits_object + * The delimits to be applied to an Object. + * @param delimits_content + * The delimits to be applied to Content. + * @param data + * The program data. + */ +#ifndef _di_fss_payload_read_print_at_extended_ + extern void fss_payload_read_print_at_extended(fss_payload_read_main_t * const main, const f_array_length_t at, const f_fss_delimits_t delimits_object, const f_fss_delimits_t delimits_content, fss_payload_read_data_t * const data) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_print_at_extended_ + +/** + * Explicitly print the Object at the given position. + * + * @param main + * The main program data. + * @param data + * The program data. + * @param at + * The index in the Objects and Contents to print. + * @param delimits_object + * The delimits to be applied to an Object. + */ +#ifndef _di_fss_payload_read_print_at_object_ + extern void fss_payload_read_print_at_object(fss_payload_read_main_t * const main, fss_payload_read_data_t * const data, const f_array_length_t at, const f_fss_delimits_t delimits_object) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_print_at_object_ + +/** + * Print total count at the specified Object/Content position for the FSS-0001 Extended Content at depth 1. + * + * @param main + * The main program data. + * @param at + * The Object/Content position. + * @param data + * The program data. + * + * @return + * F_none on success but nothig was matched (and total was printed). + * F_success on success and something was matched (and total was printed). + */ +#ifndef _di_fss_payload_read_print_at_total_extended_ + extern f_status_t fss_payload_read_print_at_total_extended(fss_payload_read_main_t * const main, const f_array_length_t at, fss_payload_read_data_t *data) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_print_at_total_extended_ + +/** + * Print the end of a Content for the FSS-0001 Extended Content at depth 1. + * + * @param main + * The main program data. + */ +#ifndef _di_fss_payload_read_print_content_end_extended_ + extern void fss_payload_read_print_content_end_extended(fss_payload_read_main_t * const main) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_print_content_end_extended_ + +/** + * Print the ignore character for Content. + * + * This is only used in pipe output mode. + * + * @param main + * The main program data. + */ +#ifndef _di_fss_payload_read_print_content_ignore_ + extern void fss_payload_read_print_content_ignore(fss_payload_read_main_t * const main) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_print_content_ignore_ + +/** + * Print the end of an Object (which is essentially the start of Content). + * + * @param main + * The main program data. + */ +#ifndef _di_fss_payload_read_print_object_end_ + extern void fss_payload_read_print_object_end(fss_payload_read_main_t * const main) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_print_object_end_ + +/** + * Print the end of an Object (which is essentially the start of Content) for the FSS-0001 Extended Content at depth 1. + * + * @param main + * The main program data. + */ +#ifndef _di_fss_payload_read_print_object_end_extended_ + extern void fss_payload_read_print_object_end_extended(fss_payload_read_main_t * const main) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_print_object_end_extended_ + +/** + * Print the number one and a newline. + * + * @param main + * The main program data. + */ +#ifndef _di_fss_payload_read_print_one_ + extern void fss_payload_read_print_one(fss_payload_read_main_t * const main) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_print_one_ + +/** + * Print the end of an Object/Content set. + * + * @param main + * The main program data. + */ +#ifndef _di_fss_payload_read_print_set_end_ + extern void fss_payload_read_print_set_end(fss_payload_read_main_t * const main) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_print_set_end_ + +/** + * Print the end of an Object/Content set for the FSS-0001 Extended Content at depth 1. + * + * @param main + * The main program data. + */ +#ifndef _di_fss_payload_read_print_set_end_extended_ + extern void fss_payload_read_print_set_end_extended(fss_payload_read_main_t * const main) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_print_set_end_extended_ + +/** + * Print the number zero and a newline. + * + * @param main + * The main program data. + */ +#ifndef _di_fss_payload_read_print_zero_ + extern void fss_payload_read_print_zero(fss_payload_read_main_t * const main) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_print_zero_ + +/** + * Perform the payload read processing on the buffer. + * + * This will print an error message on error. + * + * @param main + * The main program data. + * @param arguments + * The parameters passed to the process. + * @param data + * The program data. + * + * @return + * F_none on success. + * + * Errors (with error bit) from: fss_payload_read_load() + * Errors (with error bit) from: fss_payload_read_process_option() + * + * @see fss_payload_read_load() + * @see fss_payload_read_process_option() + */ +#ifndef _di_fss_payload_read_process_ + extern f_status_t fss_payload_read_process(fss_payload_read_main_t * const main, const f_console_arguments_t *arguments, fss_payload_read_data_t *data) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_process_ + +/** + * Process based on at parameter. + * + * @param main + * The main program data. + * @param data + * The program data. + * @param names + * An array of booleans representing whether or not some Object name is to be used. + * (If TRUE, then the name is to be used and if FALSE, then the name is not to be used.) + * + * @return + * F_none on success. + * + * @see fss_payload_read_process_at_line() + */ +#ifndef _di_fss_payload_read_process_at_ + extern f_status_t fss_payload_read_process_at(fss_payload_read_main_t * const main, fss_payload_read_data_t *data, bool names[]) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_process_at_ + +/** + * Process based on at parameter for the FSS-0001 Extended Content at depth 1. + * + * @param main + * The main program data. + * @param data + * The program data. + * @param names + * An array of booleans representing whether or not some Object name is to be used. + * (If TRUE, then the name is to be used and if FALSE, then the name is not to be used.) + * + * @return + * F_none on success. + * + * @see fss_payload_read_process_at_line() + */ +#ifndef _di_fss_payload_read_process_at_extended_ + extern f_status_t fss_payload_read_process_at_extended(fss_payload_read_main_t * const main, fss_payload_read_data_t *data, bool names[]) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_process_at_extended_ + +/** + * Process based on at parameter for some line. + * + * @param main + * The main program data. + * @param delimits_object + * The delimits to be applied to an Object. + * @param delimits_content + * The delimits to be applied to Content. + * @param data + * The program data. + * @param line + * The current line being processed. + * This will be incremented as necessary. + * + * @return + * F_none on success but no line was matched (and possibly printed). + * F_success on success and the line was matched (and possibly printed). + */ +#ifndef _di_fss_payload_read_process_at_line_ + extern f_status_t fss_payload_read_process_at_line(fss_payload_read_main_t * const main, const f_array_length_t at, const f_array_lengths_t delimits_object, const f_array_lengths_t delimits_content, fss_payload_read_data_t *data, f_array_length_t *line) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_process_at_line_ + +/** + * Process based on columns parameter. + * + * @param main + * The main program data. + * @param data + * The program data. + * @param names + * An array of booleans representing whether or not some Object name is to be used. + * (If TRUE, then the name is to be used and if FALSE, then the name is not to be used.) + * + * @return + * F_none on success. + */ +#ifndef _di_fss_payload_read_process_columns_ + extern f_status_t fss_payload_read_process_columns(fss_payload_read_main_t * const main, fss_payload_read_data_t *data, bool names[]) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_process_columns_ + +/** + * Process based on columns parameter for the FSS-0001 Extended Content at depth 1. + * + * @param main + * The main program data. + * @param data + * The program data. + * @param names + * An array of booleans representing whether or not some Object name is to be used. + * (If TRUE, then the name is to be used and if FALSE, then the name is not to be used.) + * + * @return + * F_none on success. + */ +#ifndef _di_fss_payload_read_process_columns_extended_ + extern f_status_t fss_payload_read_process_columns_extended(fss_payload_read_main_t * const main, fss_payload_read_data_t *data, bool names[]) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_process_columns_extended_ + +/** + * Process based on line parameter. + * + * @param main + * The main program data. + * @param data + * The program data. + * @param names + * An array of booleans representing whether or not some Object name is to be used. + * (If TRUE, then the name is to be used and if FALSE, then the name is not to be used.) + * + * @return + * F_none on success. + */ +#ifndef _di_fss_payload_read_process_line_ + extern f_status_t fss_payload_read_process_line(fss_payload_read_main_t * const main, fss_payload_read_data_t *data, bool names[]) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_process_line_ + +/** + * Process based on line parameter for the FSS-0001 Extended Content at depth 1. + * + * @param main + * The main program data. + * @param data + * The program data. + * @param names + * An array of booleans representing whether or not some Object name is to be used. + * (If TRUE, then the name is to be used and if FALSE, then the name is not to be used.) + * + * @return + * F_none on success. + */ +#ifndef _di_fss_payload_read_process_line_extended_ + extern f_status_t fss_payload_read_process_line_extended(fss_payload_read_main_t * const main, fss_payload_read_data_t *data, bool names[]) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_process_line_extended_ + +/** + * Process the Objects in the buffer, determining if the Object name is to be used or not. + * + * How an Object name is determined to be used or not is dependent on several parameters, such as --name, --depth, --at, and --line. + * + * @param data + * The program data. + * @param names + * An array of booleans representing whether or not some Object name is to be used. + * (If TRUE, then the name is to be used and if FALSE, then the name is not to be used.) + * + * @return + * F_none on success. + */ +#ifndef _di_fss_payload_read_process_name_ + extern f_status_t fss_payload_read_process_name(fss_payload_read_data_t *data, bool names[]) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_process_name_ + +/** + * Process the Objects in the buffer, determining if the Object name is to be used or not for the FSS-0001 Extended Content at depth 1. + * + * How an Object name is determined to be used or not is dependent on several parameters, such as --name, --depth, --at, and --line. + * + * @param data + * The program data. + * @param names + * An array of booleans representing whether or not some Object name is to be used. + * (If TRUE, then the name is to be used and if FALSE, then the name is not to be used.) + * + * @return + * F_none on success. + */ +#ifndef _di_fss_payload_read_process_name_extended_ + extern f_status_t fss_payload_read_process_name_extended(fss_payload_read_data_t *data, bool names[]) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_process_name_extended_ + +/** + * Process the parameters, populating the option property of the program data. + * + * @param main + * The main program data. + * @param arguments + * The parameters passed to the process. + * @param data + * The program data. + * + * @return + * F_none on success. + * + * Errors (with error bit) from: fss_payload_read_load_setting() + * + * @see fll_fss_payload_read() + * + * @see fss_payload_read_load_setting() + */ +#ifndef _di_fss_payload_read_process_option_ + extern f_status_t fss_payload_read_process_option(fss_payload_read_main_t * const main, const f_console_arguments_t *arguments, fss_payload_read_data_t *data) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_process_option_ + +/** + * Process based on total parameter. + * + * @param main + * The main program data. + * @param data + * The program data. + * @param names + * An array of booleans representing whether or not some Object name is to be used. + * (If TRUE, then the name is to be used and if FALSE, then the name is not to be used.) + * + * @return + * F_none on success. + */ +#ifndef _di_fss_payload_read_process_total_ + extern f_status_t fss_payload_read_process_total(fss_payload_read_main_t * const main, fss_payload_read_data_t *data, bool names[]) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_process_total_ + +/** + * Process based on total parameter for the FSS-0001 Extended Content at depth 1. + * + * @param main + * The main program data. + * @param data + * The program data. + * @param names + * An array of booleans representing whether or not some Object name is to be used. + * (If TRUE, then the name is to be used and if FALSE, then the name is not to be used.) + * + * @return + * F_none on success. + */ +#ifndef _di_fss_payload_read_process_total_extended_ + extern f_status_t fss_payload_read_process_total_extended(fss_payload_read_main_t * const main, fss_payload_read_data_t *data, bool names[]) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_read_process_total_extended_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _PRIVATE_fss_payload_read_h diff --git a/level_3/fss_payload_read/data/build/defines b/level_3/fss_payload_read/data/build/defines new file mode 100644 index 0000000..c665317 --- /dev/null +++ b/level_3/fss_payload_read/data/build/defines @@ -0,0 +1,2 @@ +# fss-0000 + diff --git a/level_3/fss_payload_read/data/build/dependencies b/level_3/fss_payload_read/data/build/dependencies new file mode 100644 index 0000000..b944420 --- /dev/null +++ b/level_3/fss_payload_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_conversion +f_directory +f_environment +f_file +f_fss +f_pipe +f_print +f_signal +fl_console +fl_conversion +fl_fss +fl_print +fl_string +fll_error +fll_file +fll_fss +fll_print +fll_program diff --git a/level_3/fss_payload_read/data/build/settings b/level_3/fss_payload_read/data/build/settings new file mode 100644 index 0000000..db7c5aa --- /dev/null +++ b/level_3/fss_payload_read/data/build/settings @@ -0,0 +1,78 @@ +# fss-0001 + +project_name fss_payload_read + +version_major 0 +version_minor 5 +version_micro 8 +version_file micro +version_target minor + +environment + +process_pre +process_post + +modes individual level monolithic +modes_default monolithic + +build_compiler gcc +build_indexer ar +build_indexer_arguments rcs +build_language c +build_libraries -lc +build_libraries-individual -lfll_error -lfll_file -lfll_fss -lfll_print -lfll_program -lfl_console -lfl_conversion -lfl_directory -lfl_fss -lfl_print -lfl_string -lf_color -lf_console -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_status_string -lf_string -lf_type_array -lf_utf +build_libraries-level -lfll_2 -lfll_1 -lfll_0 +build_libraries-monolithic -lfll +build_libraries_shared +build_libraries_static +build_sources_library fss_payload_read.c private-common.c private-fss_payload_read.c +build_sources_library_shared +build_sources_library_static +build_sources_program main.c +build_sources_program_shared +build_sources_program_static +build_sources_headers fss_payload_read.h +build_sources_headers_shared +build_sources_headers_static +build_sources_script +build_sources_setting +build_script yes +build_shared yes +build_static no + +path_headers program/fss_payload_read +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 -D_di_libcap_ -D_di_thread_support_ +defines -D_libcap_legacy_only_ -D_pthread_attr_unsupported_ -D_pthread_sigqueue_unsupported_ +defines_library +defines_library_shared +defines_library_static +defines_program +defines_program_shared +defines_program_static +defines_static +defines_shared + +flags -O2 -z now -g -fdiagnostics-color=always -Wno-logical-not-parentheses -Wno-logical-op-parentheses -Wno-parentheses +flags_library -fPIC +flags_library_shared +flags_library_static +flags_program -fPIE +flags_program_shared +flags_program_static +flags_shared +flags_static diff --git a/level_3/fss_payload_write/c/fss_payload_write.c b/level_3/fss_payload_write/c/fss_payload_write.c new file mode 100644 index 0000000..00a5950 --- /dev/null +++ b/level_3/fss_payload_write/c/fss_payload_write.c @@ -0,0 +1,566 @@ +#include "fss_payload_write.h" +#include "private-common.h" +#include "private-fss_payload_write.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fss_payload_write_print_help_ + f_status_t fss_payload_write_print_help(const f_file_t file, const f_color_context_t context) { + + flockfile(file.stream); + + fll_program_print_help_header(file, context, fss_payload_write_program_name_long_s, fss_payload_write_program_version_s); + + fll_program_print_help_option(file, context, f_console_standard_short_help_s, f_console_standard_long_help_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Print this help message."); + fll_program_print_help_option(file, context, f_console_standard_short_dark_s, f_console_standard_long_dark_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Output using colors that show up better on dark backgrounds."); + fll_program_print_help_option(file, context, f_console_standard_short_light_s, f_console_standard_long_light_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Output using colors that show up better on light backgrounds."); + fll_program_print_help_option(file, context, f_console_standard_short_no_color_s, f_console_standard_long_no_color_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, "Do not file in color."); + fll_program_print_help_option(file, context, f_console_standard_short_quiet_s, f_console_standard_long_quiet_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Decrease verbosity, silencing most output."); + fll_program_print_help_option(file, context, f_console_standard_short_normal_s, f_console_standard_long_normal_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Set verbosity to normal file."); + fll_program_print_help_option(file, context, f_console_standard_short_verbose_s, f_console_standard_long_verbose_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Increase verbosity beyond normal output."); + fll_program_print_help_option(file, context, f_console_standard_short_debug_s, f_console_standard_long_debug_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Enable debugging, significantly increasing verbosity beyond normal output."); + fll_program_print_help_option(file, context, f_console_standard_short_version_s, f_console_standard_long_version_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Print only the version number."); + + f_print_character(f_string_eol_s[0], file.stream); + + fll_program_print_help_option(file, context, fss_payload_write_short_file_s, fss_payload_write_long_file_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Specify a file to send data to."); + fll_program_print_help_option(file, context, fss_payload_write_short_content_s, fss_payload_write_long_content_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, "The Content to file."); + fll_program_print_help_option(file, context, fss_payload_write_short_double_s, fss_payload_write_long_double_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Use double quotes (default)."); + fll_program_print_help_option(file, context, fss_payload_write_short_ignore_s, fss_payload_write_long_ignore_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Ignore a given range within a Content."); + fll_program_print_help_option(file, context, fss_payload_write_short_object_s, fss_payload_write_long_object_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " The Object to file."); + fll_program_print_help_option(file, context, fss_payload_write_short_partial_s, fss_payload_write_long_partial_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, "Do not file end of Object/Content character."); + fll_program_print_help_option(file, context, fss_payload_write_short_prepend_s, fss_payload_write_long_prepend_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, "Prepend the given whitespace characters to the start of each multi-line Content."); + fll_program_print_help_option(file, context, fss_payload_write_short_single_s, fss_payload_write_long_single_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Use single quotes."); + fll_program_print_help_option(file, context, fss_payload_write_short_trim_s, fss_payload_write_long_trim_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Trim Object names."); + + fll_program_print_help_usage(file, context, fss_payload_write_program_name_s, f_string_empty_s); + + fl_print_format(" The pipe uses the Backspace character '%[\\b%]' (%[U+0008%]) to designate the start of a Content.%c", file.stream, context.set.notable, context.set.notable, context.set.notable, context.set.notable, f_string_eol_s[0]); + fl_print_format(" The pipe uses the Form Feed character '%[\\f%]' (%[U+000C%]) to designate the end of the last Content.%c", file.stream, context.set.notable, context.set.notable, context.set.notable, context.set.notable, f_string_eol_s[0]); + fl_print_format(" The pipe uses the Vertical Line character '%[\\v%]' (%[U+000B%]) is used to ignore a Content range, which does nothing in this program.%c", file.stream, context.set.notable, context.set.notable, context.set.notable, context.set.notable, f_string_eol_s[0]); + fl_print_format(" For the pipe, an Object is terminated by either a Backspace character '%[\\b%]' (%[U+0008%])", file.stream, context.set.notable, context.set.notable, context.set.notable, context.set.notable); + fl_print_format(" or a Form Feed character '%[\\f%]' (%[U+000C%]).%c", file.stream, context.set.notable, context.set.notable, context.set.notable, context.set.notable, f_string_eol_s[0]); + fl_print_format(" The end of the pipe represents the end of any Object or Content.%c%c", file.stream, f_string_eol_s[0], f_string_eol_s[0]); + + fl_print_format(" The FSS-000E (Payload) specification does not support quoted names, therefore the parameters '%[%s%s%]'", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_write_long_single_s, context.set.notable); + fl_print_format(" and '%[%s%s%]' do nothing.%c%c", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_write_long_double_s, context.set.notable, f_string_eol_s[0], f_string_eol_s[0]); + + fl_print_format(" This program does not use the parameter '%[%s%s%]', which therefore does nothing.%c", file.stream, context.set.notable, f_console_symbol_long_enable_s, fss_payload_write_long_ignore_s, context.set.notable, f_string_eol_s[0]); + fl_print_format(" This parameter requires two values.%c%c", file.stream, f_string_eol_s[0], f_string_eol_s[0]); + + funlockfile(file.stream); + + return F_none; + } +#endif // _di_fss_payload_write_print_help_ + +#ifndef _di_fss_payload_write_main_ + f_status_t fss_payload_write_main(fss_payload_write_main_t * const main, const f_console_arguments_t *arguments) { + + f_status_t status = F_none; + + { + const f_console_parameters_t parameters = macro_f_console_parameters_t_initialize(main->parameters, fss_payload_write_total_parameters_d); + + { + f_console_parameter_id_t ids[3] = { fss_payload_write_parameter_no_color_e, fss_payload_write_parameter_light_e, fss_payload_write_parameter_dark_e }; + const f_console_parameter_ids_t choices = macro_f_console_parameter_ids_t_initialize(ids, 3); + + status = fll_program_parameter_process(*arguments, parameters, choices, F_true, &main->remaining, &main->context); + + main->output.set = &main->context.set; + main->error.set = &main->context.set; + main->warning.set = &main->context.set; + + if (main->context.set.error.before) { + main->output.context = f_color_set_empty_s; + main->output.notable = main->context.set.notable; + + main->error.context = main->context.set.error; + main->error.notable = main->context.set.notable; + + main->warning.context = main->context.set.warning; + main->warning.notable = main->context.set.notable; + } + else { + f_color_set_t *sets[] = { &main->output.context, &main->output.notable, &main->error.context, &main->error.notable, &main->warning.context, &main->warning.notable, 0 }; + + fll_program_parameter_process_empty(&main->context, sets); + } + + if (F_status_is_error(status)) { + fss_payload_write_main_delete(main); + return F_status_set_error(status); + } + } + + // Identify priority of verbosity related parameters. + { + f_console_parameter_id_t ids[4] = { fss_payload_write_parameter_verbosity_quiet_e, fss_payload_write_parameter_verbosity_normal_e, fss_payload_write_parameter_verbosity_verbose_e, fss_payload_write_parameter_verbosity_debug_e }; + f_console_parameter_id_t choice = 0; + const f_console_parameter_ids_t choices = macro_f_console_parameter_ids_t_initialize(ids, 4); + + status = f_console_parameter_prioritize_right(parameters, choices, &choice); + + if (F_status_is_error(status)) { + fss_payload_write_main_delete(main); + return status; + } + + if (choice == fss_payload_write_parameter_verbosity_quiet_e) { + main->output.verbosity = f_console_verbosity_quiet_e; + main->error.verbosity = f_console_verbosity_quiet_e; + main->warning.verbosity = f_console_verbosity_quiet_e; + } + else if (choice == fss_payload_write_parameter_verbosity_normal_e) { + main->output.verbosity = f_console_verbosity_normal_e; + main->error.verbosity = f_console_verbosity_normal_e; + main->warning.verbosity = f_console_verbosity_normal_e; + } + else if (choice == fss_payload_write_parameter_verbosity_verbose_e) { + main->output.verbosity = f_console_verbosity_verbose_e; + main->error.verbosity = f_console_verbosity_verbose_e; + main->warning.verbosity = f_console_verbosity_verbose_e; + } + else if (choice == fss_payload_write_parameter_verbosity_debug_e) { + main->output.verbosity = f_console_verbosity_debug_e; + main->error.verbosity = f_console_verbosity_debug_e; + main->warning.verbosity = f_console_verbosity_debug_e; + } + } + + status = F_none; + } + + if (main->parameters[fss_payload_write_parameter_help_e].result == f_console_result_found_e) { + fss_payload_write_print_help(main->output.to, main->context); + + fss_payload_write_main_delete(main); + return status; + } + + if (main->parameters[fss_payload_write_parameter_version_e].result == f_console_result_found_e) { + fll_program_print_version(main->output.to, fss_payload_write_program_version_s); + + fss_payload_write_main_delete(main); + return status; + } + + f_file_t output = f_file_t_initialize; + + output.id = F_type_descriptor_output_d; + output.stream = main->output.to.stream; + output.flag = F_file_flag_create_d | F_file_flag_write_only_d | F_file_flag_append_d; + output.size_read = main->output.to.size_read; + output.size_write = main->output.to.size_write; + + if (F_status_is_error_not(status)) { + if (main->parameters[fss_payload_write_parameter_file_e].result == f_console_result_additional_e) { + if (main->parameters[fss_payload_write_parameter_file_e].values.used > 1) { + if (main->error.verbosity != f_console_verbosity_quiet_e) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sThe parameter '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_write_long_file_s, main->error.notable); + fl_print_format("%[' may only be specified once.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } + + status = F_status_set_error(F_parameter); + } + else { + const f_array_length_t location = main->parameters[fss_payload_write_parameter_file_e].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(main->error, F_status_set_fine(status), "f_file_stream_open", F_true, arguments->argv[location], "open", fll_error_file_type_file_e); + } + } + } + else if (main->parameters[fss_payload_write_parameter_file_e].result == f_console_result_found_e) { + fss_payload_write_error_parameter_value_missing_print(main, f_console_symbol_long_enable_s, fss_payload_write_long_file_s); + status = F_status_set_error(F_parameter); + } + } + + if (F_status_is_error_not(status)) { + if (main->parameters[fss_payload_write_parameter_object_e].locations.used || main->parameters[fss_payload_write_parameter_content_e].locations.used) { + if (main->parameters[fss_payload_write_parameter_object_e].locations.used) { + if (main->parameters[fss_payload_write_parameter_object_e].locations.used != main->parameters[fss_payload_write_parameter_object_e].values.used) { + fss_payload_write_error_parameter_value_missing_print(main, f_console_symbol_long_enable_s, fss_payload_write_long_object_s); + status = F_status_set_error(F_parameter); + } + else if (main->parameters[fss_payload_write_parameter_content_e].locations.used != main->parameters[fss_payload_write_parameter_content_e].values.used) { + fss_payload_write_error_parameter_value_missing_print(main, f_console_symbol_long_enable_s, fss_payload_write_long_content_s); + status = F_status_set_error(F_parameter); + } + else if (main->parameters[fss_payload_write_parameter_object_e].locations.used != main->parameters[fss_payload_write_parameter_content_e].locations.used && main->parameters[fss_payload_write_parameter_partial_e].result == f_console_result_none_e) { + fss_payload_write_error_parameter_same_times_print(main); + status = F_status_set_error(F_parameter); + } + else if (main->parameters[fss_payload_write_parameter_content_e].locations.used && main->parameters[fss_payload_write_parameter_partial_e].locations.used) { + if (main->parameters[fss_payload_write_parameter_content_e].result == f_console_result_additional_e) { + if (main->error.verbosity != f_console_verbosity_quiet_e) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sThe '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_write_long_partial_s, main->error.notable); + fl_print_format("%[' parameter only allows either the '%]", main->error.to.stream, main->error.context, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_write_long_object_s, main->error.notable); + fl_print_format("%[' parameter or the '%]", main->error.to.stream, main->error.context, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_write_long_content_s, main->error.notable); + fl_print_format("%[' parameter, but not both.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } + + status = F_status_set_error(F_parameter); + } + } + + if (F_status_is_error_not(status)) { + if (main->parameters[fss_payload_write_parameter_content_e].result == f_console_result_additional_e) { + 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 < main->parameters[fss_payload_write_parameter_object_e].locations.used; ++i) { + location_object = main->parameters[fss_payload_write_parameter_object_e].locations.array[i]; + location_content = main->parameters[fss_payload_write_parameter_content_e].locations.array[i]; + location_sub_object = main->parameters[fss_payload_write_parameter_object_e].locations_sub.array[i]; + location_sub_content = main->parameters[fss_payload_write_parameter_content_e].locations_sub.array[i]; + + if (location_object > location_content || location_object == location_content && location_sub_object > location_sub_content) { + if (main->error.verbosity != f_console_verbosity_quiet_e) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sEach '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_write_long_object_s, main->error.notable); + fl_print_format("%[' parameter must be specified before a '%]", main->error.to.stream, main->error.context, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_write_long_content_s, main->error.notable); + fl_print_format("%[' parameter.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } + + status = F_status_set_error(F_parameter); + break; + } + } // for + } + } + } + else if (main->parameters[fss_payload_write_parameter_content_e].locations.used) { + if (main->parameters[fss_payload_write_parameter_content_e].locations.used != main->parameters[fss_payload_write_parameter_content_e].values.used) { + fss_payload_write_error_parameter_value_missing_print(main, f_console_symbol_long_enable_s, fss_payload_write_long_content_s); + status = F_status_set_error(F_parameter); + } + else if (!main->parameters[fss_payload_write_parameter_partial_e].locations.used) { + fss_payload_write_error_parameter_same_times_print(main); + status = F_status_set_error(F_parameter); + } + } + } + else if (!main->process_pipe) { + if (main->error.verbosity != f_console_verbosity_quiet_e) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sThis requires either piped data or the use of the '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_write_long_object_s, main->error.notable); + fl_print_format("%[' parameter with the '%]", main->error.to.stream, main->error.context, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_write_long_content_s, main->error.notable); + fl_print_format("%[' parameter.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } + + status = F_status_set_error(F_parameter); + } + + if (F_status_is_error_not(status) && main->process_pipe) { + if (main->parameters[fss_payload_write_parameter_partial_e].result == f_console_result_found_e) { + if (main->error.verbosity != f_console_verbosity_quiet_e) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sThis '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_write_long_partial_s, main->error.notable); + fl_print_format("%[' parameter cannot be used when processing a pipe.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } + + status = F_status_set_error(F_parameter); + } + } + } + + if (F_status_is_error_not(status)) { + if (main->parameters[fss_payload_write_parameter_prepend_e].result == f_console_result_found_e) { + if (main->error.verbosity != f_console_verbosity_quiet_e) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sThe parameter '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_write_long_prepend_s, main->error.notable); + fl_print_format("%[' is specified, but no value is given.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } + + status = F_status_set_error(F_parameter); + } + else if (main->parameters[fss_payload_write_parameter_prepend_e].result == f_console_result_additional_e) { + const f_array_length_t index = main->parameters[fss_payload_write_parameter_prepend_e].values.array[main->parameters[fss_payload_write_parameter_prepend_e].values.used - 1]; + const f_array_length_t length = strnlen(arguments->argv[index], f_console_parameter_size); + + if (length) { + f_string_range_t range = macro_f_string_range_t_initialize(length); + + main->prepend.string = arguments->argv[index]; + main->prepend.used = length; + main->prepend.size = length; + + for (; range.start < length; range.start++) { + + status = f_fss_is_space(main->prepend, range); + if (F_status_is_error(status)) break; + + if (status == F_false) { + if (main->error.verbosity != f_console_verbosity_quiet_e) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sThe value for the parameter '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_write_long_prepend_s, main->error.notable); + fl_print_format("%[' must only contain whitespace.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } + + status = F_status_set_error(F_parameter); + break; + } + } // for + } + else { + if (main->error.verbosity != f_console_verbosity_quiet_e) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sThe value for the parameter '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_write_long_prepend_s, main->error.notable); + fl_print_format("%[' must not be an empty string.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } + + status = F_status_set_error(F_parameter); + } + } + } + + if (F_status_is_error_not(status)) { + if (main->parameters[fss_payload_write_parameter_ignore_e].result == f_console_result_found_e) { + if (main->error.verbosity != f_console_verbosity_quiet_e) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sThe parameter '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_write_long_ignore_s, main->error.notable); + fl_print_format("%[' was specified, but no values were given.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } + + status = F_status_set_error(F_parameter); + } + else if (main->parameters[fss_payload_write_parameter_ignore_e].result == f_console_result_additional_e) { + const f_array_length_t total_locations = main->parameters[fss_payload_write_parameter_ignore_e].locations.used; + const f_array_length_t total_arguments = main->parameters[fss_payload_write_parameter_ignore_e].values.used; + + if (total_locations * 2 > total_arguments) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sThe parameter '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_write_long_ignore_s, main->error.notable); + fl_print_format("%[' requires two values.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + + status = F_status_set_error(F_parameter); + } + } + } + + f_fss_quote_t quote = F_fss_delimit_quote_double_s; + + if (F_status_is_error_not(status)) { + if (main->parameters[fss_payload_write_parameter_double_e].result == f_console_result_found_e) { + if (main->parameters[fss_payload_write_parameter_single_e].result == f_console_result_found_e) { + if (main->parameters[fss_payload_write_parameter_double_e].location < main->parameters[fss_payload_write_parameter_single_e].location) { + quote = F_fss_delimit_quote_single_s; + } + } + } + else if (main->parameters[fss_payload_write_parameter_single_e].result == f_console_result_found_e) { + quote = F_fss_delimit_quote_single_s; + } + } + + 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; + + // @todo Go through the list of Objects, if given, and confirm that payload is specified and is specified last, otherwise error out. + // @todo a new parameter needs to exist for specifying that a Content is a payload for cases where Object is not given (and then this needs to verify that only a single Content is given). + + if (F_status_is_error_not(status)) { + f_string_dynamic_t escaped = f_string_dynamic_t_initialize; + + if (main->process_pipe) { + status = fss_payload_write_process_pipe(main, output, quote, &buffer); + + if (F_status_is_error(status)) { + if (main->error.verbosity != f_console_verbosity_quiet_e) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sWhile processing the '%]%[input pipe%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context, main->error.notable, main->error.notable); + fl_print_format("%['.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } + } + } + + if (F_status_is_error_not(status)) { + if (main->parameters[fss_payload_write_parameter_partial_e].result == f_console_result_found_e) { + + if (main->parameters[fss_payload_write_parameter_object_e].result == f_console_result_additional_e) { + for (f_array_length_t i = 0; i < main->parameters[fss_payload_write_parameter_object_e].values.used; ++i) { + + if (fss_payload_write_signal_received(main)) { + status = F_status_set_error(F_interrupt); + break; + } + + object.string = arguments->argv[main->parameters[fss_payload_write_parameter_object_e].values.array[i]]; + object.used = strnlen(object.string, f_console_parameter_size); + object.size = object.used; + + status = fss_payload_write_process(main, output, quote, &object, 0, &buffer); + if (F_status_is_error(status)) break; + } // for + } + else { + for (f_array_length_t i = 0; i < main->parameters[fss_payload_write_parameter_content_e].values.used; ++i) { + + if (fss_payload_write_signal_received(main)) { + status = F_status_set_error(F_interrupt); + break; + } + + content.string = arguments->argv[main->parameters[fss_payload_write_parameter_content_e].values.array[i]]; + content.used = strnlen(content.string, f_console_parameter_size); + content.size = content.used; + + status = fss_payload_write_process(main, output, quote, 0, &content, &buffer); + if (F_status_is_error(status)) break; + } // for + } + } + else { + for (f_array_length_t i = 0; i < main->parameters[fss_payload_write_parameter_object_e].values.used; ++i) { + + if (fss_payload_write_signal_received(main)) { + status = F_status_set_error(F_interrupt); + break; + } + + object.string = arguments->argv[main->parameters[fss_payload_write_parameter_object_e].values.array[i]]; + object.used = strnlen(object.string, f_console_parameter_size); + object.size = object.used; + + content.string = arguments->argv[main->parameters[fss_payload_write_parameter_content_e].values.array[i]]; + content.used = strnlen(content.string, f_console_parameter_size); + content.size = content.used; + + status = fss_payload_write_process(main, output, quote, &object, &content, &buffer); + if (F_status_is_error(status)) break; + } // for + } + + if (F_status_is_error(status)) { + if (main->error.verbosity != f_console_verbosity_quiet_e) { + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sWhile processing the '%]%[input arguments%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context, main->error.notable, main->error.notable); + fl_print_format("%['.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } + } + else if (main->error.verbosity != f_console_verbosity_quiet_e && main->parameters[fss_payload_write_parameter_file_e].result == f_console_result_none_e) { + + // Ensure there is always a newline at the end, unless in quiet mode. + fll_print_character(f_string_eol_s[0], main->output.to.stream); + } + } + + macro_f_string_dynamic_t_delete_simple(escaped); + + // Object and content, though being a "dynamic" type, is being used statically, so clear them up to avoid invalid free(). + object.string = 0; + object.used = 0; + object.size = 0; + + content.string = 0; + content.used = 0; + content.size = 0; + } + + if (main->parameters[fss_payload_write_parameter_file_e].result == f_console_result_additional_e) { + 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 (main->error.verbosity != f_console_verbosity_quiet_e) { + if (F_status_is_error(status)) { + fll_print_character(f_string_eol_s[0], main->error.to.stream); + } + } + + macro_f_string_dynamic_t_delete_simple(buffer); + macro_f_string_dynamic_t_delete_simple(object); + macro_f_string_dynamic_t_delete_simple(content); + fss_payload_write_main_delete(main); + + return status; + } +#endif // _di_fss_payload_write_main_ + +#ifndef _di_fss_payload_write_main_delete_ + f_status_t fss_payload_write_main_delete(fss_payload_write_main_t * const main) { + + for (f_array_length_t i = 0; i < fss_payload_write_total_parameters_d; ++i) { + + macro_f_array_lengths_t_delete_simple(main->parameters[i].locations); + macro_f_array_lengths_t_delete_simple(main->parameters[i].locations_sub); + macro_f_array_lengths_t_delete_simple(main->parameters[i].values); + } // for + + macro_f_array_lengths_t_delete_simple(main->remaining); + + macro_f_color_context_t_delete_simple(main->context); + + return F_none; + } +#endif // _di_fss_payload_write_main_delete_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_3/fss_payload_write/c/fss_payload_write.h b/level_3/fss_payload_write/c/fss_payload_write.h new file mode 100644 index 0000000..1cc387d --- /dev/null +++ b/level_3/fss_payload_write/c/fss_payload_write.h @@ -0,0 +1,241 @@ +/** + * FLL - Level 3 + * + * Project: FSS + * API Version: 0.5 + * Licenses: lgpl-2.1-or-later + * + * This program provides fss basic list write functionality. + */ +#ifndef _fss_payload_write_h + +// libc includes +#include +#include +#include +#include + +// fll-0 includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// fll-1 includes +#include +#include +#include +#include + +// fll-2 includes +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fss_payload_write_program_version_ + #define fss_payload_write_program_version_major_s F_string_ascii_0_s + #define fss_payload_write_program_version_minor_s F_string_ascii_5_s + #define fss_payload_write_program_version_micro_s F_string_ascii_8_s + + #ifndef fss_payload_write_program_version_nano_prefix_s + #define fss_payload_write_program_version_nano_prefix_s + #endif + + #ifndef fss_payload_write_program_version_nano_s + #define fss_payload_write_program_version_nano_s + #endif + + #define fss_payload_write_program_version_s fss_payload_write_program_version_major_s F_string_ascii_period_s fss_payload_write_program_version_minor_s F_string_ascii_period_s fss_payload_write_program_version_micro_s fss_payload_write_program_version_nano_prefix_s fss_payload_write_program_version_nano_s +#endif // _di_fss_payload_write_program_version_ + +#ifndef _di_fss_payload_write_program_name_ + #define fss_payload_write_program_name_s "fss_payload_write" + #define fss_payload_write_program_name_long_s "FSS Basic List Write" +#endif // _di_fss_payload_write_program_name_ + +#ifndef _di_fss_payload_write_defines_ + #define fss_payload_write_signal_check_d 10000 + + #define fss_payload_write_pipe_content_end_s '\f' + #define fss_payload_write_pipe_content_ignore_s '\v' + #define fss_payload_write_pipe_content_start_s '\b' + + #define fss_payload_write_short_file_s "f" + #define fss_payload_write_short_content_s "c" + #define fss_payload_write_short_double_s "d" + #define fss_payload_write_short_ignore_s "I" + #define fss_payload_write_short_object_s "o" + #define fss_payload_write_short_partial_s "p" + #define fss_payload_write_short_prepend_s "P" + #define fss_payload_write_short_single_s "s" + #define fss_payload_write_short_trim_s "T" + + #define fss_payload_write_long_file_s "file" + #define fss_payload_write_long_content_s "content" + #define fss_payload_write_long_double_s "double" + #define fss_payload_write_long_ignore_s "ignore" + #define fss_payload_write_long_object_s "object" + #define fss_payload_write_long_partial_s "partial" + #define fss_payload_write_long_prepend_s "prepend" + #define fss_payload_write_long_single_s "single" + #define fss_payload_write_long_trim_s "trim" + + enum { + fss_payload_write_parameter_help_e, + fss_payload_write_parameter_light_e, + fss_payload_write_parameter_dark_e, + fss_payload_write_parameter_no_color_e, + fss_payload_write_parameter_verbosity_quiet_e, + fss_payload_write_parameter_verbosity_normal_e, + fss_payload_write_parameter_verbosity_verbose_e, + fss_payload_write_parameter_verbosity_debug_e, + fss_payload_write_parameter_version_e, + + fss_payload_write_parameter_file_e, + fss_payload_write_parameter_content_e, + fss_payload_write_parameter_double_e, + fss_payload_write_parameter_ignore_e, + fss_payload_write_parameter_object_e, + fss_payload_write_parameter_partial_e, + fss_payload_write_parameter_prepend_e, + fss_payload_write_parameter_single_e, + fss_payload_write_parameter_trim_e, + }; + + #define fss_payload_write_console_parameter_t_initialize \ + { \ + f_console_parameter_t_initialize(f_console_standard_short_help_s, f_console_standard_long_help_s, 0, 0, f_console_type_normal_e), \ + f_console_parameter_t_initialize(f_console_standard_short_light_s, f_console_standard_long_light_s, 0, 0, f_console_type_inverse_e), \ + f_console_parameter_t_initialize(f_console_standard_short_dark_s, f_console_standard_long_dark_s, 0, 0, f_console_type_inverse_e), \ + f_console_parameter_t_initialize(f_console_standard_short_no_color_s, f_console_standard_long_no_color_s, 0, F_false, f_console_type_inverse_e), \ + f_console_parameter_t_initialize(f_console_standard_short_quiet_s, f_console_standard_long_quiet_s, 0, 0, f_console_type_inverse_e), \ + f_console_parameter_t_initialize(f_console_standard_short_normal_s, f_console_standard_long_normal_s, 0, 0, f_console_type_inverse_e), \ + f_console_parameter_t_initialize(f_console_standard_short_verbose_s, f_console_standard_long_verbose_s, 0, 0, f_console_type_inverse_e), \ + f_console_parameter_t_initialize(f_console_standard_short_debug_s, f_console_standard_long_debug_s, 0, 0, f_console_type_inverse_e), \ + f_console_parameter_t_initialize(f_console_standard_short_version_s, f_console_standard_long_version_s, 0, 0, f_console_type_inverse_e), \ + f_console_parameter_t_initialize(fss_payload_write_short_file_s, fss_payload_write_long_file_s, 0, 1, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_write_short_content_s, fss_payload_write_long_content_s, 0, 1, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_write_short_double_s, fss_payload_write_long_double_s, 0, 0, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_write_short_ignore_s, fss_payload_write_long_ignore_s, 0, 2, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_write_short_object_s, fss_payload_write_long_object_s, 0, 1, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_write_short_partial_s, fss_payload_write_long_partial_s, 0, 0, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_write_short_prepend_s, fss_payload_write_long_prepend_s, 0, 1, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_write_short_single_s, fss_payload_write_long_single_s, 0, 0, f_console_type_normal_e), \ + f_console_parameter_t_initialize(fss_payload_write_short_trim_s, fss_payload_write_long_trim_s, 0, 0, f_console_type_normal_e), \ + } + + #define fss_payload_write_total_parameters_d 18 +#endif // _di_fss_payload_write_defines_ + +#ifndef _di_fss_payload_write_main_t_ + typedef struct { + f_console_parameter_t parameters[fss_payload_write_total_parameters_d]; + + f_array_lengths_t remaining; + bool process_pipe; + + fl_print_t output; + fl_print_t error; + fl_print_t warning; + + f_signal_t signal; + + f_string_static_t prepend; + + f_color_context_t context; + } fss_payload_write_main_t; + + #define fss_payload_write_main_t_initialize \ + { \ + fss_payload_write_console_parameter_t_initialize, \ + f_array_lengths_t_initialize, \ + F_false, \ + fl_print_t_initialize, \ + macro_fl_print_t_initialize_error(), \ + macro_fl_print_t_initialize_warning(), \ + f_signal_t_initialize, \ + f_string_static_t_initialize, \ + f_color_context_t_initialize, \ + } +#endif // _di_fss_payload_write_main_t_ + +/** + * Print help. + * + * @param file + * The file to print to. + * @param context + * The color context settings. + * + * @return + * F_none on success. + */ +#ifndef _di_fss_payload_write_print_help_ + extern f_status_t fss_payload_write_print_help(const f_file_t file, const f_color_context_t context); +#endif // _di_fss_payload_write_print_help_ + +/** + * Execute main program. + * + * Be sure to call fss_payload_write_main_delete() after executing this. + * + * If main.signal is non-zero, then this blocks and handles the following signals: + * - F_signal_abort + * - F_signal_broken_pipe + * - F_signal_hangup + * - F_signal_interrupt + * - F_signal_quit + * - F_signal_termination + * + * @param main + * The main program data. + * @param arguments + * The parameters passed to the process. + * + * @return + * F_none on success. + * + * Status codes (with error bit) are returned on any problem. + * + * @see fss_payload_write_main_delete() + */ +#ifndef _di_fss_payload_write_main_ + extern f_status_t fss_payload_write_main(fss_payload_write_main_t * const main, const f_console_arguments_t *arguments); +#endif // _di_fss_payload_write_main_ + +/** + * Deallocate main. + * + * Be sure to call this after executing fss_payload_write_main(). + * + * @param main + * The main program data. + * + * @return + * F_none on success. + * + * Status codes (with error bit) are returned on any problem. + * + * @see fss_payload_write_main() + */ +#ifndef _di_fss_payload_write_main_delete_ + extern f_status_t fss_payload_write_main_delete(fss_payload_write_main_t * const main); +#endif // _di_fss_payload_write_main_delete_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _fss_payload_write_h diff --git a/level_3/fss_payload_write/c/main.c b/level_3/fss_payload_write/c/main.c new file mode 100644 index 0000000..85b72ae --- /dev/null +++ b/level_3/fss_payload_write/c/main.c @@ -0,0 +1,53 @@ +#include "fss_payload_write.h" + +int main(const int argc, const f_string_t *argv) { + + const f_console_arguments_t arguments = { argc, argv }; + fss_payload_write_main_t data = fss_payload_write_main_t_initialize; + + if (f_pipe_input_exists()) { + data.process_pipe = F_true; + } + + // Handle signals so that program can cleanly exit, deallocating as appropriate. + { + f_signal_set_empty(&data.signal.set); + f_signal_set_add(F_signal_abort, &data.signal.set); + f_signal_set_add(F_signal_broken_pipe, &data.signal.set); + f_signal_set_add(F_signal_hangup, &data.signal.set); + f_signal_set_add(F_signal_interrupt, &data.signal.set); + f_signal_set_add(F_signal_quit, &data.signal.set); + f_signal_set_add(F_signal_termination, &data.signal.set); + + f_status_t status = f_signal_mask(SIG_BLOCK, &data.signal.set, 0); + + if (F_status_is_error_not(status)) { + status = f_signal_open(&data.signal); + + // If there is an error opening a signal descriptor, then do not handle signals. + if (F_status_is_error(status)) { + f_signal_mask(SIG_UNBLOCK, &data.signal.set, 0); + f_signal_close(&data.signal); + } + } + } + + const f_status_t status = fss_payload_write_main(&data, &arguments); + + // Flush output pipes before closing. + fflush(F_type_output_d); + fflush(F_type_error_d); + + // Close all open file descriptors. + close(F_type_descriptor_output_d); + close(F_type_descriptor_input_d); + close(F_type_descriptor_error_d); + + f_signal_close(&data.signal); + + if (F_status_is_error(status)) { + return 1; + } + + return 0; +} diff --git a/level_3/fss_payload_write/c/private-common.c b/level_3/fss_payload_write/c/private-common.c new file mode 100644 index 0000000..7851de3 --- /dev/null +++ b/level_3/fss_payload_write/c/private-common.c @@ -0,0 +1,57 @@ +#include "fss_payload_write.h" +#include "private-common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fss_payload_write_print_signal_received_ + void fss_payload_write_print_signal_received(fss_payload_write_main_t * const main, const f_status_t signal) { + + if (main->warning.verbosity != f_console_verbosity_verbose_e) return; + + // Must flush and reset color because the interrupt may have interrupted the middle of a print function. + fflush(main->warning.to.stream); + + flockfile(main->warning.to.stream); + + fl_print_format("%]%c%c%[Received signal code %]", main->warning.to.stream, main->context.set.reset, f_string_eol_s[0], f_string_eol_s[0], main->context.set.warning, main->context.set.warning); + fl_print_format("%[%i%]", main->warning.to.stream, main->context.set.notable, signal, main->context.set.notable); + fl_print_format("%[.%]%c", main->warning.to.stream, main->context.set.warning, main->context.set.warning, f_string_eol_s[0]); + + funlockfile(main->warning.to.stream); + } +#endif // _di_fss_payload_write_print_signal_received_ + +#ifndef _di_fss_payload_write_signal_received_ + f_status_t fss_payload_write_signal_received(fss_payload_write_main_t * const main) { + + if (main->signal.id == -1) { + return F_false; + } + + struct signalfd_siginfo information; + + memset(&information, 0, sizeof(struct signalfd_siginfo)); + + if (f_signal_read(main->signal, 0, &information) == F_signal) { + switch (information.ssi_signo) { + case F_signal_abort: + case F_signal_broken_pipe: + case F_signal_hangup: + case F_signal_interrupt: + case F_signal_quit: + case F_signal_termination: + fss_payload_write_print_signal_received(main, information.ssi_signo); + + return information.ssi_signo; + } + } + + return F_false; + } +#endif // _di_fss_payload_write_signal_received_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_3/fss_payload_write/c/private-common.h b/level_3/fss_payload_write/c/private-common.h new file mode 100644 index 0000000..340fb78 --- /dev/null +++ b/level_3/fss_payload_write/c/private-common.h @@ -0,0 +1,61 @@ +/** + * FLL - Level 3 + * + * Project: FSS Basic List Write + * API Version: 0.5 + * Licenses: lgpl-2.1-or-later + */ +#ifndef _PRIVATE_common_h +#define _PRIVATE_common_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Provide common/generic definitions. + * + * payload_write_common_allocation_*: + * - large: An allocation step used for buffers that are anticipated to have large buffers. + * - small: An allocation step used for buffers that are anticipated to have small buffers. + */ +#ifndef _di_fss_payload_write_common_ + #define fss_payload_write_common_allocation_large_d 256 + #define fss_payload_write_common_allocation_small_d 16 +#endif // _di_fss_payload_write_common_ + +/** + * Print a message about a process signal being recieved, such as an interrupt signal. + * + * @param main + * The main program data. + * @param signal + * The signal received. + */ +#ifndef _di_fss_payload_write_print_signal_received_ + extern void fss_payload_write_print_signal_received(fss_payload_write_main_t * const main, const f_status_t signal) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_write_print_signal_received_ + +/** + * Check to see if a process signal is received. + * + * Only signals that are blocked via main.signal will be received. + * + * @param main + * The main program data. + * + * @return + * A positive number representing a valid signal on signal received. + * F_false on no signal received. + * + * @see f_signal_read() + */ +#ifndef _di_fss_payload_write_signal_received_ + extern f_status_t fss_payload_write_signal_received(fss_payload_write_main_t * const main) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_write_signal_received_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _PRIVATE_common_h diff --git a/level_3/fss_payload_write/c/private-fss_payload_write.c b/level_3/fss_payload_write/c/private-fss_payload_write.c new file mode 100644 index 0000000..5db4116 --- /dev/null +++ b/level_3/fss_payload_write/c/private-fss_payload_write.c @@ -0,0 +1,399 @@ +#include "fss_payload_write.h" +#include "private-common.h" +#include "private-fss_payload_write.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fss_payload_write_error_parameter_same_times_print_ + void fss_payload_write_error_parameter_same_times_print(fss_payload_write_main_t * const main) { + + if (main->error.verbosity == f_console_verbosity_quiet_e) { + return; + } + + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sMust specify the '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_write_long_object_s, main->error.notable); + fl_print_format("%[' parameter and the '%]", main->error.to.stream, main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_write_long_content_s, main->error.notable); + fl_print_format("%[' parameter the same number of times when not specifying the '%]", main->error.to.stream, main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%s%s%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, fss_payload_write_long_partial_s, main->error.notable); + fl_print_format("%[' parameter.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } +#endif // _di_fss_payload_write_error_parameter_same_times_print_ + +#ifndef _di_fss_payload_write_error_parameter_unsupported_eol_print_ + void fss_payload_write_error_parameter_unsupported_eol_print(fss_payload_write_main_t * const main) { + + if (main->error.verbosity == f_console_verbosity_quiet_e) { + return; + } + + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sThis standard does not support end of line character '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[\\n%]", main->error.to.stream, main->error.notable, main->error.notable); + fl_print_format("%[' in objects.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } +#endif // _di_fss_payload_write_error_parameter_unsupported_eol_print_ + +#ifndef _di_fss_payload_write_error_parameter_value_missing_print_ + void fss_payload_write_error_parameter_value_missing_print(fss_payload_write_main_t * const main, const f_string_t symbol, const f_string_t parameter) { + + if (main->error.verbosity == f_console_verbosity_quiet_e) { + return; + } + + flockfile(main->error.to.stream); + + fl_print_format("%c%[%sThe parameter '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context); + fl_print_format("%[%S%S%]", main->error.to.stream, main->error.notable, symbol, parameter, main->error.notable); + fl_print_format("%[' is specified, but no value is given.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } +#endif // _di_fss_payload_write_error_parameter_value_missing_print_ + +#ifndef _di_fss_payload_write_process_ + f_status_t fss_payload_write_process(fss_payload_write_main_t * const main, const f_file_t output, const f_fss_quote_t quote, const f_string_static_t *object, const f_string_static_t *content, f_string_dynamic_t *buffer) { + + f_status_t status = F_none; + f_state_t state = macro_f_state_t_initialize(fss_payload_write_common_allocation_large_d, fss_payload_write_common_allocation_small_d, 0, 0, 0, 0, 0); + f_string_range_t range = f_string_range_t_initialize; + + if (object) { + if (content) { + bool trim = F_false; + + if (main->parameters[fss_payload_write_parameter_trim_e].result == f_console_result_found_e) { + trim = F_true; + } + + if (object->used) { + range.start = 0; + range.stop = object->used - 1; + } + else { + range.start = 1; + range.stop = 0; + } + + status = fll_fss_payload_write_string(*object, *content, trim, &main->prepend, state, buffer); + + if (F_status_set_fine(status) == F_none_eol) { + fss_payload_write_error_parameter_unsupported_eol_print(main); + + return F_status_set_error(F_supported_not); + } + + if (F_status_is_error(status)) { + fll_error_print(main->error, F_status_set_fine(status), "fll_fss_payload_write_string", F_true); + + return status; + } + } + else { + uint8_t complete = f_fss_complete_none_e; + + if (object->used) { + range.start = 0; + range.stop = object->used - 1; + } + else { + range.start = 1; + range.stop = 0; + } + + if (content) { + if (main->parameters[fss_payload_write_parameter_trim_e].result == f_console_result_found_e) { + complete = f_fss_complete_full_trim_e; + } + else { + complete = f_fss_complete_full_e; + } + } + + status = fl_fss_basic_list_object_write(*object, complete, state, &range, buffer); + + if (F_status_set_fine(status) == F_none_eol) { + fss_payload_write_error_parameter_unsupported_eol_print(main); + + return F_status_set_error(F_supported_not); + } + + if (F_status_is_error(status)) { + fll_error_print(main->error, F_status_set_fine(status), "fl_fss_basic_list_object_write", F_true); + + return status; + } + } + } + else { + if (content && content->used) { + range.start = 0; + range.stop = content->used - 1; + + status = fl_fss_basic_list_content_write(*content, object ? f_fss_complete_full_e : f_fss_complete_none_e, &main->prepend, state, &range, buffer); + + if (F_status_is_error(status)) { + fll_error_print(main->error, F_status_set_fine(status), "fl_fss_payload_content_write", F_true); + + return status; + } + } + } + + if (!object || !content) { + status = f_string_append(f_string_eol_s, 1, buffer); + + if (F_status_is_error(status)) { + fll_error_print(main->error, F_status_set_fine(status), "f_string_append", F_true); + + return status; + } + } + + fll_print_dynamic(*buffer, output.stream); + + buffer->used = 0; + + return status; + } +#endif // _di_fss_payload_write_process_ + +#ifndef _di_fss_payload_write_process_pipe_ + f_status_t fss_payload_write_process_pipe(fss_payload_write_main_t * const main, const f_file_t output, const f_fss_quote_t quote, f_string_dynamic_t *buffer) { + + f_status_t status = F_none; + f_status_t status_pipe = F_none; + + f_file_t input = f_file_t_initialize; + + input.id = F_type_descriptor_input_d; + input.size_read = 2048; + + f_array_length_t total = 0; + f_array_length_t previous = 0; + f_string_range_t range = f_string_range_t_initialize; + + f_string_dynamic_t block = f_string_dynamic_t_initialize; + f_string_dynamic_t object = f_string_dynamic_t_initialize; + f_string_dynamic_t content = f_string_dynamic_t_initialize; + + // 0x0 = start new object/content set, 0x1 = processing object, 0x2 = processing content, 0x3 = end object/content set, 0x4 = processing payload content. + uint8_t state = 0; + + for (;;) { + + if (fss_payload_write_signal_received(main)) { + status = F_status_set_error(F_interrupt); + + break; + } + + 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(main->error, F_status_set_fine(status_pipe), "f_file_read_block", F_true); + + status_pipe = F_status_set_error(F_pipe); + + break; + } + + if (!block.used) break; + + range.start = 0; + range.stop = block.used - 1; + } + + if (!state || state == 0x1) { + if (!state) { + object.used = 0; + content.used = 0; + + state = 0x1; + } + + if (object.used + block.used > object.size) { + status = f_string_dynamic_increase_by(block.used, &object); + + if (F_status_is_error(status)) { + fll_error_print(main->error, F_status_set_fine(status), "f_string_dynamic_increase_by", F_true); + + break; + } + } + + for (; range.start <= range.stop; ++range.start) { + + if (block.string[range.start] == fss_payload_write_pipe_content_start_s) { + state = 0x2; + ++range.start; + + break; + } + + if (block.string[range.start] == fss_payload_write_pipe_content_end_s) { + state = 0x3; + ++range.start; + + break; + } + + if (block.string[range.start] == fss_payload_write_pipe_content_ignore_s) { + + // 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; + } + + // When payload is provided, all data at this point is part of the payload until the end of the pipe. + if (fl_string_dynamic_compare_string(f_fss_string_payload_s, object, F_fss_string_payload_s_length) == F_equal_to) { + if (total > 1) { + + // The first character is the terminating new line, which is not part of the payload. + ++range.start; + --total; + + status = f_string_dynamic_increase_by(total, &content); + + if (F_status_is_error(status)) { + fll_error_print(main->error, F_status_set_fine(status), "f_string_dynamic_increase_by", F_true); + + break; + } + + memcpy(content.string, block.string + range.start, total); + + content.used += total; + } + + state = 0x4; + + // Designate to read next block from pipe. + range.start = 1; + range.stop = 0; + + continue; + } + + if (total) { + status = f_string_dynamic_increase_by(total, &content); + + if (F_status_is_error(status)) { + fll_error_print(main->error, F_status_set_fine(status), "f_string_dynamic_increase_by", F_true); + + break; + } + + for (; range.start <= range.stop; ++range.start) { + + if (block.string[range.start] == fss_payload_write_pipe_content_start_s) { + if (main->error.verbosity != f_console_verbosity_quiet_e) { + fll_print_format("%c%[%sThis standard only supports one content per object.%]%c", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context, f_string_eol_s[0]); + } + + status = F_status_set_error(F_supported_not); + + break; + } + + if (block.string[range.start] == fss_payload_write_pipe_content_end_s) { + state = 0x3; + ++range.start; + + break; + } + + if (block.string[range.start] == fss_payload_write_pipe_content_ignore_s) { + + // This is not used by this program. + 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_payload_write_process(main, output, quote, &object, &content, buffer); + if (F_status_is_error(status)) break; + + state = 0; + } + + if (state == 0x4) { + if (block.used) { + status = f_string_dynamic_increase_by(block.used, &content); + + if (F_status_is_error(status)) { + fll_error_print(main->error, F_status_set_fine(status), "f_string_dynamic_increase_by", F_true); + + break; + } + + memcpy(content.string, block.string, block.used); + + content.used += block.used; + } + + // Designate to read next block from pipe. + range.start = 1; + range.stop = 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_payload_write_process(main, output, quote, &object, &content, buffer); + } + + macro_f_string_dynamic_t_delete_simple(block); + macro_f_string_dynamic_t_delete_simple(object); + macro_f_string_dynamic_t_delete_simple(content); + + return status; + } +#endif // _di_fss_payload_write_process_pipe_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_3/fss_payload_write/c/private-fss_payload_write.h b/level_3/fss_payload_write/c/private-fss_payload_write.h new file mode 100644 index 0000000..8ecf302 --- /dev/null +++ b/level_3/fss_payload_write/c/private-fss_payload_write.h @@ -0,0 +1,101 @@ +/** + * FLL - Level 3 + * + * Project: FSS + * API Version: 0.5 + * Licenses: lgpl-2.1-or-later + */ +#ifndef _PRIVATE_fss_payload_write_h +#define _PRIVATE_fss_payload_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 main + * The main program data. + */ +#ifndef _di_fss_payload_write_error_parameter_same_times_print_ + void fss_payload_write_error_parameter_same_times_print(fss_payload_write_main_t * const main) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_write_error_parameter_same_times_print_ + +/** + * Print an message about a parameter EOL being unsupported. + * + * @param main + * The main program data. + */ +#ifndef _di_fss_payload_write_error_parameter_unsupported_eol_print_ + void fss_payload_write_error_parameter_unsupported_eol_print(fss_payload_write_main_t * const main) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_write_error_parameter_unsupported_eol_print_ + +/** + * Print an message about a parameter missing a value. + * + * @param main + * The main program data. + * @param symbol + * The console symbol, such as "--" in "--help". + * @param parameter + * The parameter name, such as "help" in "--help". + */ +#ifndef _di_fss_payload_write_error_parameter_value_missing_print_ + void fss_payload_write_error_parameter_value_missing_print(fss_payload_write_main_t * const main, const f_string_t symbol, const f_string_t parameter) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_write_error_parameter_value_missing_print_ + +/** + * Process a given object and content, printing the FSS if valid or an error if invalid. + * + * @param main + * The main 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 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_payload_write_process_ + extern f_status_t fss_payload_write_process(fss_payload_write_main_t * const main, const f_file_t output, const f_fss_quote_t quote, const f_string_static_t *object, const f_string_static_t *content, f_string_dynamic_t *buffer) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_write_process_ + +/** + * Process the pipe, reading from the pipe and writing to the output. + * + * @param main + * The main program data. + * @param output + * The file to output to. + * @param quote + * The quote character to use. + * This is either single our double quote. + * @param buffer + * The buffer array used as a cache to construct the output before printing. + * + * @return + * F_none on success. + * F_failure (with error bit) for any othe failure. + */ +#ifndef _di_fss_payload_write_process_pipe_ + extern f_status_t fss_payload_write_process_pipe(fss_payload_write_main_t * const main, const f_file_t output, const f_fss_quote_t quote, f_string_dynamic_t *buffer) F_attribute_visibility_internal_d; +#endif // _di_fss_payload_write_process_pipe_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _PRIVATE_fss_payload_write_h diff --git a/level_3/fss_payload_write/data/build/defines b/level_3/fss_payload_write/data/build/defines new file mode 100644 index 0000000..c665317 --- /dev/null +++ b/level_3/fss_payload_write/data/build/defines @@ -0,0 +1,2 @@ +# fss-0000 + diff --git a/level_3/fss_payload_write/data/build/dependencies b/level_3/fss_payload_write/data/build/dependencies new file mode 100644 index 0000000..b944420 --- /dev/null +++ b/level_3/fss_payload_write/data/build/dependencies @@ -0,0 +1,27 @@ +# fss-0000 + +f_type +f_status +f_memory +f_string +f_utf +f_color +f_console +f_conversion +f_directory +f_environment +f_file +f_fss +f_pipe +f_print +f_signal +fl_console +fl_conversion +fl_fss +fl_print +fl_string +fll_error +fll_file +fll_fss +fll_print +fll_program diff --git a/level_3/fss_payload_write/data/build/settings b/level_3/fss_payload_write/data/build/settings new file mode 100644 index 0000000..4386341 --- /dev/null +++ b/level_3/fss_payload_write/data/build/settings @@ -0,0 +1,78 @@ +# fss-0001 + +project_name fss_payload_write + +version_major 0 +version_minor 5 +version_micro 8 +version_file micro +version_target minor + +environment + +process_pre +process_post + +modes individual level monolithic +modes_default monolithic + +build_compiler gcc +build_indexer ar +build_indexer_arguments rcs +build_language c +build_libraries -lc +build_libraries-individual -lfll_error -lfll_file -lfll_fss -lfll_print -lfll_program -lfl_console -lfl_conversion -lfl_directory -lfl_fss -lfl_print -lfl_string -lf_color -lf_console -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_status_string -lf_string -lf_type_array -lf_utf +build_libraries-level -lfll_2 -lfll_1 -lfll_0 +build_libraries-monolithic -lfll +build_libraries_shared +build_libraries_static +build_sources_library fss_payload_write.c private-common.c private-fss_payload_write.c +build_sources_library_shared +build_sources_library_static +build_sources_program main.c +build_sources_program_shared +build_sources_program_static +build_sources_headers fss_payload_write.h +build_sources_headers_shared +build_sources_headers_static +build_sources_script +build_sources_setting +build_script yes +build_shared yes +build_static no + +path_headers program/fss_payload_write +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 -D_di_libcap_ -D_di_thread_support_ +defines -D_libcap_legacy_only_ -D_pthread_attr_unsupported_ -D_pthread_sigqueue_unsupported_ +defines_library +defines_library_shared +defines_library_static +defines_program +defines_program_shared +defines_program_static +defines_static +defines_shared + +flags -O2 -z now -g -fdiagnostics-color=always -Wno-logical-not-parentheses -Wno-logical-op-parentheses -Wno-parentheses +flags_library -fPIC +flags_library_shared +flags_library_static +flags_program -fPIE +flags_program_shared +flags_program_static +flags_shared +flags_static diff --git a/specifications/fss-000e.txt b/specifications/fss-000e.txt index a1f9744..ebc3be8 100644 --- a/specifications/fss-000e.txt +++ b/specifications/fss-000e.txt @@ -18,6 +18,7 @@ Featureless Settings Specification: 000e - Payload: The payload is terminated by the EOF (end of file) character or when a designated "length" is reached. Nothing in the payload may be considered a valid list Object and therefore there will be no escaping allowed. Comments are not considered comments inside the payload and are considered part of the payload. + The payload may be empty (length may be zero), but the list Object "payload" must still exist. Other than the reserved list Objects "header" and "payload" any other valid Object may be specified.