]> Kevux Git Server - fll/commitdiff
Update: IKI Read design and logic to be consistency with 0.7 logic.
authorKevin Day <Kevin@kevux.org>
Thu, 2 Jan 2025 04:19:21 +0000 (22:19 -0600)
committerKevin Day <Kevin@kevux.org>
Thu, 2 Jan 2025 04:19:21 +0000 (22:19 -0600)
This fixes some logic problems and oversights regarding IKI Read.

Several of the "problems" are really just functionality that is operating inconsistently with the FSS Read programs.
The logic is updated to be more reasonable and to better hand fail cases without throwing as many errors.

The logic is back ported, but much of the design is different between the 0.6 and 0.7 code.
Rather than re-design the 0.6, I sort of wedged the logic changes in place.
I'm not particularly happy about this but I think this is good enough.

A lot of the changes made have been done sporadically in random moments of time that I have had available on my holiday.
The code quality is likely not up to my usual.

The newly added unit tests are being used to direct the correctness of the program.
The only problem being that the unit tests are newly added and are themselves not well reviewed.

I am hoping to focus on the 0.7 development this year of 2025.
This means my focus on some of the 0.6 code is going to be waning.

I don't expect much changes on the 0.6 code anyway and the changes to the IKI Read are an exceptional case.

187 files changed:
level_3/iki_read/c/private-print.c
level_3/iki_read/c/private-print.h
level_3/iki_read/c/private-read.c
level_3/iki_read/c/private-read.h
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-0-at-0-name-is-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-0-at-0-name-is.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-0-at-0-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-0-at-0-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-0-at-1-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-0-at-1-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-0-name-is-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-0-name-is.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-0-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-0-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-1-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-1-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-1-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-1-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-10-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-10-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-10-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-100-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-100-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-100-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-2-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-2-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-2-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-20-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-20-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-20-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-3-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-3-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-3-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-4-at-0-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-4-at-0-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-4-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-4-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-4-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-4-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-4-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-5-at-0-name-is-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-5-at-0-name-is.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-5-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-5-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-5-name-is-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-5-name-is.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-5-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-6-at-0-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-6-at-0-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-6-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-6-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-6-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-6-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-6-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-7-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-7-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-7-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-8-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-8-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-8-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-9-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-9-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-content-line-9-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-0-at-0-name-is-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-0-at-0-name-is.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-0-at-0-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-0-at-0-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-0-at-1-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-0-at-1-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-0-name-is-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-0-name-is.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-0-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-0-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-1-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-1-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-1-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-1-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-10-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-10-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-10-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-100-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-100-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-100-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-2-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-2-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-2-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-20-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-20-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-20-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-3-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-3-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-3-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-4-at-0-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-4-at-0-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-4-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-4-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-4-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-4-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-4-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-5-at-0-name-is-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-5-at-0-name-is.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-5-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-5-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-5-name-is-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-5-name-is.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-5-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-6-at-0-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-6-at-0-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-6-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-6-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-6-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-6-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-6-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-7-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-7-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-7-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-8-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-8-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-8-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-9-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-9-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-literal-line-9-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-0-at-0-name-is-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-0-at-0-name-is.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-0-at-0-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-0-at-0-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-0-at-1-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-0-at-1-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-0-name-is-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-0-name-is.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-0-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-0-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-1-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-1-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-1-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-1-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-10-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-10-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-10-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-100-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-100-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-100-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-2-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-2-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-2-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-20-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-20-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-20-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-3-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-3-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-3-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-4-at-0-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-4-at-0-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-4-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-4-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-4-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-4-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-4-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-5-at-0-name-is-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-5-at-0-name-is.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-5-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-5-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-5-name-is-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-5-name-is.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-5-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-6-at-0-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-6-at-0-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-6-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-6-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-6-name-yup-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-6-name-yup.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-6-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-7-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-7-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-7-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-8-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-8-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-8-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-9-at-0-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-9-at-1-total.expect
level_3/iki_read/tests/runtime/iki/expect/test-0000-basic-object-line-9-total.expect

index 163f3f2acb98ede0b4afc8c49158dc3599591c1c..6882f3d5424956f75d5bd89c64c10ca6630f1363 100644 (file)
@@ -158,6 +158,105 @@ extern "C" {
   }
 #endif // _di_iki_read_substitutions_print_
 
+#ifndef _di_iki_read_line_print_
+  f_status_t iki_read_line_print(iki_read_data_t * const data, fl_print_t * const print, const f_string_dynamic_t expand) {
+
+    if (!data || !print) return F_status_set_error(F_parameter);
+    if (!expand.used) return F_data_not;
+
+    f_number_unsigned_t i = 0;
+    f_string_range_t range = macro_f_string_range_t_initialize2(expand.used);
+    f_status_t status;
+
+    for (f_number_unsigned_t first = 0; range.start <= range.stop && range.start < expand.used; ) {
+
+      if (!((++data->main->signal_check) % iki_read_signal_check_d)) {
+        if (fll_program_standard_signal_received(data->main)) {
+          iki_read_print_signal_received(data);
+
+          return F_status_set_error(F_interrupt);
+        }
+
+        data->main->signal_check = 0;
+      }
+
+      status = f_string_dynamic_seek_line(expand, &range);
+      if (F_status_is_error(status)) return status;
+
+      if (status == F_none) {
+        if (i == data->line) {
+          range.stop = range.start;
+          range.start = first;
+
+          f_print_dynamic_partial(expand, range, print->to.stream);
+
+          break;
+        }
+        else {
+          first = ++range.start;
+          ++i;
+        }
+      }
+      else {
+        if (i == data->line) {
+          range.stop = range.start;
+          range.start = first;
+
+          f_print_dynamic_partial(expand, range, print->to.stream);
+          f_print_dynamic(f_string_eol_s, print->to.stream);
+        }
+
+        break;
+      }
+    } // for
+
+    return F_none;
+  }
+#endif // _di_iki_read_line_print_
+
+#ifndef _di_iki_read_line_total_expand_print_
+  f_status_t iki_read_line_total_expand_print(iki_read_data_t * const data, fl_print_t * const print, const f_string_dynamic_t expand) {
+
+    if (!data || !print) return F_status_set_error(F_parameter);
+
+    f_number_unsigned_t total = 0;
+
+    {
+      f_status_t status = F_none;
+      f_string_range_t range = macro_f_string_range_t_initialize2(expand.used);
+
+      for (; range.start <= range.stop && range.start < expand.used; ++total, ++range.start) {
+
+        if (!((++data->main->signal_check) % iki_read_signal_check_d)) {
+          if (fll_program_standard_signal_received(data->main)) {
+            iki_read_print_signal_received(data);
+
+            return F_status_set_error(F_interrupt);
+          }
+
+          data->main->signal_check = 0;
+        }
+
+        status = f_string_dynamic_seek_line(expand, &range);
+        if (F_status_is_error(status)) return status;
+      } // for
+    }
+
+    fll_print_format(
+      "%ul%r",
+      print->to.stream,
+      data->main->parameters.array[iki_read_parameter_line_e].result == f_console_result_additional_e
+        ? data->line < total ? 1 : 0
+        : total,
+      f_string_eol_s
+    );
+
+    return data->main->parameters.array[iki_read_parameter_line_e].result == f_console_result_additional_e
+      ? data->line < total ? F_none : F_data_not
+      : total ? F_none : F_data_not;
+  }
+#endif // _di_iki_read_line_total_expand_print_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index c1c1580f79d93bb6fa8ac7e9fa11cbdf5f88fa47..2df9f1bf6e74c3f28eaf53929482e6337c5cf13f 100644 (file)
@@ -40,6 +40,59 @@ extern "C" {
   extern void iki_read_substitutions_print(iki_read_data_t * const data, const f_iki_data_t iki_data, const f_string_ranges_t ranges, const iki_read_substitution_t replacement, const iki_read_substitution_t wraps, const iki_read_substitutions_t substitutions, const iki_read_substitutions_t reassignments, const f_array_length_t index, const bool content_only) F_attribute_visibility_internal_d;
 #endif // _di_iki_read_substitutions_print_
 
+/**
+ * Print the data from the expand cache at the line.
+ *
+ * This requires that the expand cache is properly populated.
+ * The expand cache may be empty.
+ *
+ * @param data
+ *   The program data
+ * @param print
+ *   The output structure to print to.
+ * @param expand
+ *   The expanded cache to count the total of.
+ *
+ * @return
+ *     F_none on success.
+ *     F_data_not on success, but total is 0 or line is out of range.
+ *
+ *     F_parameter (with error bit) on invalid parameter.
+ *
+ *     Error (with error bit set) from f_string_dynamic_seek_line().
+ */
+#ifndef _di_iki_read_line_print_
+  extern f_status_t iki_read_line_print(iki_read_data_t * const data, fl_print_t * const print, const f_string_dynamic_t expand) F_attribute_visibility_internal_d;
+#endif // _di_iki_read_line_print_
+
+/**
+ * Count and print the total from the data in the expand cache at the line.
+ *
+ * This requires that the expand cache is properly populated.
+ * The expand cache may be empty.
+ *
+ * This only checks if the flag iki_read_main_flag_line_d is set.
+ * Otherwise, the total lines from the expand cache is counted as-is.
+ *
+ * @param data
+ *   The program data
+ * @param print
+ *   The output structure to print to.
+ * @param expand
+ *   The expanded cache to count the total of.
+ *
+ * @return
+ *     F_none on success.
+ *     F_data_not on success, but total is 0 or line is out of range.
+ *
+ *     F_parameter (with error bit) on invalid parameter.
+ *
+ *     Error (with error bit set) from f_string_dynamic_seek_line().
+ */
+#ifndef _di_iki_read_line_total_expand_print_
+  extern f_status_t iki_read_line_total_expand_print(iki_read_data_t * const data, fl_print_t * const print, const f_string_dynamic_t expand) F_attribute_visibility_internal_d;
+#endif // _di_iki_read_line_total_expand_print_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 8c063a45f481c6c5e6fabd0747c4b89a9b4523ec..d24bfcb000aba74280d878073c338758113ea3a5 100644 (file)
@@ -99,6 +99,184 @@ extern "C" {
   }
 #endif // _di_iki_read_process_buffer_
 
+#ifndef _di_iki_read_process_buffer_at_
+  f_status_t iki_read_process_buffer_at(iki_read_data_t * const data, const f_iki_data_t iki_data, const iki_read_substitution_t replacement, const iki_read_substitution_t wrap, const iki_read_substitutions_t substitutions, const iki_read_substitutions_t reassignments, const f_number_unsigned_t index, f_string_dynamic_t * const expand) {
+
+    if (!data) return F_status_set_error(F_parameter);
+
+    const f_number_unsigned_t original = expand->used;
+
+    if (index >= iki_data.vocabulary.used) return F_data_not;
+
+    f_number_unsigned_t i = reassignments.used;
+    f_string_range_t range = f_string_range_t_initialize;
+    f_status_t status = F_none;
+
+    if (reassignments.used && (data->main->parameters.array[iki_read_parameter_content_e].result == f_console_result_found_e || data->main->parameters.array[iki_read_parameter_literal_e].result == f_console_result_found_e)) {
+      if (reassignments.used) {
+        i = reassignments.used - 1;
+      }
+    }
+
+    if (i < reassignments.used) {
+      if (data->main->parameters.array[iki_read_parameter_content_e].result == f_console_result_found_e) {
+        status = f_string_dynamic_append_nulless(reassignments.array[i].with, expand);
+      }
+      else {
+        range.start = iki_data.variable.array[index].start;
+        range.stop = iki_data.content.array[index].start - 1;
+
+        status = f_string_dynamic_partial_append_nulless(data->buffer, range, expand);
+
+        if (F_status_is_error_not(status)) {
+          status = f_string_dynamic_append_nulless(reassignments.array[i].with, expand);
+        }
+
+        if (F_status_is_error_not(status)) {
+          range.start = iki_data.content.array[index].stop + 1;
+          range.stop = iki_data.variable.array[index].stop;
+
+          status = f_string_dynamic_partial_append_nulless(data->buffer, range, expand);
+        }
+      }
+    }
+    else {
+      i = substitutions.used;
+
+      if (substitutions.used && (data->main->parameters.array[iki_read_parameter_content_e].result == f_console_result_found_e || data->main->parameters.array[iki_read_parameter_literal_e].result == f_console_result_found_e )) {
+        if (substitutions.used) {
+          i = substitutions.used - 1;
+        }
+      }
+
+      if (i < substitutions.used) {
+        if (data->main->parameters.array[iki_read_parameter_content_e].result == f_console_result_found_e && wrap.replace.used) {
+          status = f_string_dynamic_append_nulless(wrap.replace, expand);
+
+          if (F_status_is_error_not(status)) {
+            status = f_string_dynamic_append_nulless(substitutions.array[i].with, expand);
+          }
+
+          if (F_status_is_error_not(status) && wrap.with.used) {
+            status = f_string_dynamic_append_nulless(wrap.with, expand);
+          }
+        }
+        else {
+          range.start = iki_data.variable.array[index].start;
+          range.stop = iki_data.content.array[index].start - 1;
+
+          status = f_string_dynamic_partial_append_nulless(data->buffer, range, expand);
+
+          if (F_status_is_error_not(status) && wrap.replace.used) {
+            status = f_string_dynamic_append_nulless(wrap.replace, expand);
+          }
+
+          if (F_status_is_error_not(status)) {
+            status = f_string_dynamic_append_nulless(substitutions.array[i].with, expand);
+          }
+
+          if (F_status_is_error_not(status) && wrap.with.used) {
+            status = f_string_dynamic_append_nulless(wrap.with, expand);
+          }
+
+          if (F_status_is_error_not(status)) {
+            range.start = iki_data.content.array[index].stop + 1;
+            range.stop = iki_data.variable.array[index].stop;
+
+            status = f_string_dynamic_partial_append_nulless(data->buffer, range, expand);
+          }
+        }
+      }
+      else if (replacement.replace.used) {
+        if (data->main->parameters.array[iki_read_parameter_content_e].result == f_console_result_found_e && wrap.replace.used) {
+          status = f_string_dynamic_append_nulless(wrap.replace, expand);
+
+          if (F_status_is_error_not(status) && replacement.with.used) {
+            status = f_string_dynamic_append_nulless(replacement.with, expand);
+          }
+
+          if (F_status_is_error_not(status) && wrap.with.used) {
+            status = f_string_dynamic_append_nulless(wrap.with, expand);
+          }
+        }
+        else if (data->main->parameters.array[iki_read_parameter_object_e].result == f_console_result_found_e) {
+          status = f_string_dynamic_append_nulless(replacement.replace, expand);
+        }
+        else {
+          range.start = iki_data.variable.array[index].start;
+          range.stop = iki_data.content.array[index].start - 1;
+
+          status = f_string_dynamic_partial_append_nulless(data->buffer, range, expand);
+
+          if (F_status_is_error_not(status) && wrap.replace.used) {
+            status = f_string_dynamic_append_nulless(wrap.replace, expand);
+          }
+
+          if (F_status_is_error_not(status)) {
+            status = f_string_dynamic_append_nulless(replacement.with, expand);
+          }
+
+          if (F_status_is_error_not(status) && wrap.with.used) {
+            status = f_string_dynamic_append_nulless(wrap.with, expand);
+          }
+
+          if (F_status_is_error_not(status)) {
+            range.start = iki_data.content.array[index].stop + 1;
+            range.stop = iki_data.variable.array[index].stop;
+
+            status = f_string_dynamic_partial_append_nulless(data->buffer, range, expand);
+          }
+        }
+      }
+      else if (data->main->parameters.array[iki_read_parameter_content_e].result == f_console_result_found_e) {
+        if (wrap.replace.used) {
+          status = f_string_dynamic_append_nulless(wrap.replace, expand);
+        }
+
+        if (F_status_is_error_not(status)) {
+          status = f_string_dynamic_partial_append_nulless(data->buffer, iki_data.content.array[index], expand);
+        }
+
+        if (F_status_is_error_not(status) && wrap.with.used) {
+          status = f_string_dynamic_append_nulless(wrap.with, expand);
+        }
+      }
+      else if (data->main->parameters.array[iki_read_parameter_object_e].result == f_console_result_found_e) {
+        status = f_string_dynamic_partial_append_nulless(data->buffer, iki_data.vocabulary.array[index], expand);
+      }
+      else {
+        range.start = iki_data.variable.array[index].start;
+        range.stop = iki_data.content.array[index].start - 1;
+
+        status = f_string_dynamic_partial_append_nulless(data->buffer, range, expand);
+
+        if (F_status_is_error_not(status) && wrap.replace.used) {
+          status = f_string_dynamic_append_nulless(wrap.replace, expand);
+        }
+
+        if (F_status_is_error_not(status)) {
+          status = f_string_dynamic_partial_append_nulless(data->buffer, iki_data.content.array[index], expand);
+        }
+
+        if (F_status_is_error_not(status) && wrap.with.used) {
+          status = f_string_dynamic_append_nulless(wrap.with, expand);
+        }
+
+        if (F_status_is_error_not(status)) {
+          range.start = iki_data.content.array[index].stop + 1;
+          range.stop = iki_data.variable.array[index].stop;
+
+          status = f_string_dynamic_partial_append_nulless(data->buffer, range, expand);
+        }
+      }
+    }
+
+    if (F_status_is_error(status)) return status;
+
+    return expand->used == original ? F_data_not : F_none;
+  }
+#endif // _di_iki_read_process_buffer_at_
+
 #ifndef _di_iki_read_process_buffer_ranges_
   f_status_t iki_read_process_buffer_ranges(iki_read_data_t * const data, f_string_range_t *buffer_range, f_iki_data_t *iki_data, f_string_ranges_t *ranges) {
 
@@ -116,17 +294,15 @@ extern "C" {
       return status;
     }
 
-    if (data->main->parameters.array[iki_read_parameter_total_e].result == f_console_result_found_e && data->main->parameters.array[iki_read_parameter_name_e].result == f_console_result_none_e) {
-      fll_print_format(
-        "%ul%r",
-        data->main->output.to.stream,
-        (data->main->parameters.array[iki_read_parameter_at_e].result == f_console_result_additional_e)
-          ? data->at < iki_data->variable.used ? 1 : 0
-          : iki_data->variable.used,
-        f_string_eol_s
-      );
+    // When --at and --line are specified, the only value for --line that will print anything is 0 when using --object.
+    if (data->main->parameters.array[iki_read_parameter_at_e].result == f_console_result_additional_e && data->main->parameters.array[iki_read_parameter_line_e].result == f_console_result_additional_e) {
+      if (data->mode == iki_read_mode_object_e && data->line) {
+        if (data->main->parameters.array[iki_read_parameter_total_e].result == f_console_result_found_e) {
+          fll_print_format("0%r", data->main->output.to.stream, f_string_eol_s);
+        }
 
-      return F_none;
+        return F_data_not;
+      }
     }
 
     f_array_length_t i = 0;
@@ -135,9 +311,6 @@ extern "C" {
       data->buffer.string[iki_data->delimits.array[i]] = f_iki_syntax_placeholder_s.string[0];
     } // for
 
-    const bool content_only = data->mode == iki_read_mode_content_e;
-    bool unmatched = F_true;
-
     iki_read_substitution_t replacements[iki_data->variable.used];
     iki_read_substitution_t wraps[iki_data->variable.used];
     iki_read_substitutions_t reassignments[iki_data->variable.used];
@@ -148,7 +321,7 @@ extern "C" {
     memset(reassignments, 0, sizeof(iki_read_substitutions_t) * iki_data->variable.used);
     memset(substitutionss, 0, sizeof(iki_read_substitutions_t) * iki_data->variable.used);
 
-    if (data->mode == iki_read_mode_literal_e || (data->mode == iki_read_mode_content_e && data->main->parameters.array[iki_read_parameter_total_e].result == f_console_result_none_e)) {
+    if (data->mode == iki_read_mode_literal_e || data->mode == iki_read_mode_content_e) {
       status = iki_read_replacements_identify(data, &iki_data->vocabulary, replacements);
 
       if (F_status_is_error(status)) {
@@ -186,107 +359,174 @@ extern "C" {
       }
     }
 
+    const bool content_only = data->mode == iki_read_mode_content_e;
+    f_string_dynamic_t expand = f_string_dynamic_t_initialize;
+
     if (data->main->parameters.array[iki_read_parameter_name_e].result == f_console_result_additional_e) {
       f_string_dynamic_t name = f_string_dynamic_t_initialize;
-
       f_array_length_t index = 0;
       f_array_length_t j = 0;
       f_array_length_t matches = 0;
+      uint8_t matched = 0x0; // 0x0 = unmatched, 0x1 = matched.
+      uint8_t errors = 0x0; // 0x0 = dynamic append, 0x1 = process buffer at.
 
       buffer_range->start = 0;
 
-      for (i = 0; i < data->main->parameters.array[iki_read_parameter_name_e].values.used; ++i) {
+      if (data->main->parameters.array[iki_read_parameter_name_e].values.used) {
+
+        // Only the last name parameter is valid for use.
+        i = data->main->parameters.array[iki_read_parameter_name_e].values.used - 1;
 
         index = data->main->parameters.array[iki_read_parameter_name_e].values.array[i];
         name.used = 0;
 
         status = f_string_dynamic_append_nulless(data->argv[index], &name);
 
-        if (F_status_is_error(status)) {
-          fll_error_print(data->main->error, F_status_set_fine(status), "f_string_dynamic_append_nulless", F_true);
+        if (F_status_is_error_not(status)) {
+          buffer_range->stop = name.used - 1;
 
-          for (j = 0; j < iki_data->variable.used; ++j) {
-            macro_iki_read_substitutions_t_delete_simple(reassignments[j]);
-          } // for
-
-          for (j = 0; j < iki_data->variable.used; ++j) {
-            macro_iki_read_substitutions_t_delete_simple(substitutionss[j]);
-          } // for
+          for (j = 0; j < iki_data->vocabulary.used; ++j) {
 
-          f_string_dynamic_resize(0, &name);
+            status = fl_string_dynamic_partial_compare(name, data->buffer, *buffer_range, iki_data->vocabulary.array[j]);
 
-          return status;
-        }
+            if (status == F_equal_to) {
+              matched |= 0x1;
 
-        buffer_range->stop = name.used - 1;
+              if (data->main->parameters.array[iki_read_parameter_at_e].result == f_console_result_additional_e) {
+                if (matches < data->at) {
+                  matches++;
 
-        flockfile(data->main->output.to.stream);
+                  continue;
+                }
 
-        for (j = 0; j < iki_data->vocabulary.used; ++j) {
+                if (matches++ > data->at) break;
+              }
 
-          // The variable parts, when not using --wrap, each is represented on its own line.
-          if (data->main->parameters.array[iki_read_parameter_line_e].result == f_console_result_additional_e) {
-            if (j < data->line) continue;
-            if (j > data->line) break;
-          }
+              if (data->main->parameters.array[iki_read_parameter_total_e].result == f_console_result_found_e) {
+                if (data->main->parameters.array[iki_read_parameter_at_e].result == f_console_result_none_e) {
+                  ++matches;
+                }
 
-          status = fl_string_dynamic_partial_compare(name, data->buffer, *buffer_range, iki_data->vocabulary.array[j]);
+                if (data->main->parameters.array[iki_read_parameter_at_e].result == f_console_result_additional_e || data->main->parameters.array[iki_read_parameter_line_e].result == f_console_result_additional_e) {
+                  status = iki_read_process_buffer_at(data, *iki_data, replacements[j], wraps[j], substitutionss[j], reassignments[j], j, &expand);
 
-          if (status == F_equal_to) {
-            unmatched = F_false;
+                  if (F_status_is_error(status)) {
+                    errors = 0x1;
 
-            if (data->main->parameters.array[iki_read_parameter_at_e].result == f_console_result_additional_e) {
-              if (matches++ != data->at) continue;
-            }
+                    break;
+                  }
 
-            if (data->main->parameters.array[iki_read_parameter_total_e].result == f_console_result_found_e) {
-              if (data->main->parameters.array[iki_read_parameter_at_e].result == f_console_result_none_e) {
-                ++matches;
+                  status = f_string_dynamic_append_nulless(f_string_eol_s, &expand);
+                  if (F_status_is_error(status)) break;
+                }
               }
-            }
-            else {
-              if (replacements[j].replace.used || wraps[j].replace.used || wraps[j].with.used || substitutionss[j].used || reassignments[j].used) {
-                iki_read_substitutions_print(data, *iki_data, *ranges, replacements[j], wraps[j], substitutionss[j], reassignments[j], j, content_only);
+              else if (data->main->parameters.array[iki_read_parameter_line_e].result == f_console_result_additional_e) {
+                status = iki_read_process_buffer_at(data, *iki_data, replacements[j], wraps[j], substitutionss[j], reassignments[j], j, &expand);
+
+                if (F_status_is_error(status)) {
+                  errors = 0x1;
+
+                  break;
+                }
+
+                status = f_string_dynamic_append_nulless(f_string_eol_s, &expand);
+                if (F_status_is_error(status)) break;
               }
               else {
-                f_print_dynamic_partial(data->buffer, ranges->array[j], data->main->output.to.stream);
-              }
+                flockfile(data->main->output.to.stream);
+
+                if (replacements[j].replace.used || wraps[j].replace.used || wraps[j].with.used || substitutionss[j].used || reassignments[j].used) {
+                  iki_read_substitutions_print(data, *iki_data, *ranges, replacements[j], wraps[j], substitutionss[j], reassignments[j], j, content_only);
+                }
+                else {
+                  f_print_dynamic_partial(data->buffer, ranges->array[j], data->main->output.to.stream);
+                }
+
+                f_print_dynamic_raw(f_string_eol_s, data->main->output.to.stream);
 
-              f_print_dynamic_raw(f_string_eol_s, data->main->output.to.stream);
+                funlockfile(data->main->output.to.stream);
+              }
             }
-          }
-        } // for
+          } // for
+        }
 
-        funlockfile(data->main->output.to.stream);
-      } // for
+        if (F_status_is_error(status)) {
+          fll_error_print(data->main->error, F_status_set_fine(status), errors ? "iki_read_process_buffer_at" : "f_string_dynamic_append_nulless", F_true);
 
-      if (data->main->parameters.array[iki_read_parameter_total_e].result == f_console_result_found_e) {
-        fll_print_format(
-          "%ul%r",
-          data->main->output.to.stream,
-          data->main->parameters.array[iki_read_parameter_at_e].result == f_console_result_additional_e
-            ? data->at < matches ? 1 : 0
-            : matches,
-          f_string_eol_s
-        );
-      }
+          for (j = 0; j < iki_data->variable.used; ++j) {
+            macro_iki_read_substitutions_t_delete_simple(reassignments[j]);
+          } // for
 
-      f_string_dynamic_resize(0, &name);
+          for (j = 0; j < iki_data->variable.used; ++j) {
+            macro_iki_read_substitutions_t_delete_simple(substitutionss[j]);
+          } // for
+
+          f_string_dynamic_resize(0, &name);
+          f_string_dynamic_resize(0, &expand);
+
+          return status;
+        }
+      }
 
-      if (unmatched) {
-        status = F_data_not;
+      if (data->main->parameters.array[iki_read_parameter_line_e].result == f_console_result_additional_e) {
+        if (data->main->parameters.array[iki_read_parameter_total_e].result == f_console_result_found_e) {
+          iki_read_line_total_expand_print(data, &data->main->output, expand);
+        }
+        else {
+          iki_read_line_print(data, &data->main->output, expand);
+        }
       }
-      else {
-        status = F_none;
+      else if (data->main->parameters.array[iki_read_parameter_total_e].result == f_console_result_found_e) {
+        if (data->main->parameters.array[iki_read_parameter_at_e].result == f_console_result_additional_e) {
+          iki_read_line_total_expand_print(data, &data->main->output, expand);
+        }
+        else {
+          fll_print_format("%ul%r", data->main->output.to.stream, matches, f_string_eol_s);
+        }
       }
+
+      f_string_dynamic_resize(0, &name);
+
+      status = matched ? F_none : F_data_not;
     }
     else if (ranges->used) {
       f_array_length_t line = 0;
 
       if (data->main->parameters.array[iki_read_parameter_at_e].result == f_console_result_additional_e) {
+        if (data->main->parameters.array[iki_read_parameter_total_e].result == f_console_result_found_e) {
+          if (data->mode != iki_read_mode_object_e || data->main->parameters.array[iki_read_parameter_line_e].result == f_console_result_additional_e) {
+            if (data->at < iki_data->variable.used) {
+              status = iki_read_process_buffer_at(data, *iki_data, replacements[data->at], wraps[data->at], substitutionss[data->at], reassignments[data->at], data->at, &expand);
+            }
+            else {
+              status = F_status_set_error(F_parameter);
+            }
+
+            if (F_status_is_error(status)) {
+              fll_error_print(data->main->error, F_status_set_fine(status), "iki_read_process_buffer_at", F_true);
+            }
+            else {
+              status = f_string_dynamic_append_nulless(f_string_eol_s, &expand);
+
+              if (F_status_is_error(status)) {
+                fll_error_print(data->main->error, F_status_set_fine(status), "f_string_dynamic_append_nulless", F_true);
+              }
+              else {
+                status = iki_read_line_total_expand_print(data, &data->main->output, expand);
+
+                if (F_status_is_error(status)) {
+                  fll_error_print(data->main->error, F_status_set_fine(status), "iki_read_process_buffer_at", F_true);
+                }
+              }
+            }
+          }
+          else {
+            fll_print_format("1%r", data->main->output.to.stream, f_string_eol_s);
+          }
+        }
 
         // The --line is processed after the --at and so any value greater than 0 should produce no results.
-        if (data->at < ranges->used && (data->main->parameters.array[iki_read_parameter_line_e].result != f_console_result_additional_e || data->line == 0)) {
+        else if (data->at < ranges->used && (data->main->parameters.array[iki_read_parameter_line_e].result != f_console_result_additional_e || data->line == 0)) {
           flockfile(data->main->output.to.stream);
 
           if (replacements[data->at].replace.used || wraps[data->at].replace.used || wraps[data->at].with.used || substitutionss[data->at].used || reassignments[data->at].used) {
@@ -306,11 +546,77 @@ extern "C" {
           status = F_data_not;
         }
       }
+      else if (data->main->parameters.array[iki_read_parameter_total_e].result == f_console_result_found_e) {
+        if (data->mode == iki_read_mode_object_e) {
+          fll_print_format(
+            "%ul%r",
+            data->main->output.to.stream,
+            (data->main->parameters.array[iki_read_parameter_line_e].result == f_console_result_additional_e)
+              ? data->line < iki_data->variable.used ? 1 : 0
+              : iki_data->variable.used,
+            f_string_eol_s
+          );
+        }
+        else {
+          for (i = 0; i < ranges->used; ++i) {
+
+            if (!((++data->main->signal_check) % iki_read_signal_check_d)) {
+              if (fll_program_standard_signal_received(data->main)) {
+                iki_read_print_signal_received(data);
+
+                status = F_status_set_error(F_interrupt);
+
+                break;
+              }
+
+              data->main->signal_check = 0;
+            }
+
+            status = iki_read_process_buffer_at(data, *iki_data, replacements[i], wraps[i], substitutionss[i], reassignments[i], i, &expand);
+
+            if (F_status_is_error(status)) {
+              fll_error_print(data->main->error, F_status_set_fine(status), "iki_read_process_buffer_at", F_true);
+
+              break;
+            }
+
+            status = f_string_dynamic_append_nulless(f_string_eol_s, &expand);
+
+            if (F_status_is_error(status)) {
+              fll_error_print(data->main->error, F_status_set_fine(status), "f_string_dynamic_append_nulless", F_true);
+
+              break;
+            }
+          } // for
+
+          if (F_status_is_error_not(status)) {
+            status = iki_read_line_total_expand_print(data, &data->main->output, expand);
+
+            if (F_status_is_error(status)) {
+              fll_error_print(data->main->error, F_status_set_fine(status), "iki_read_process_buffer_at", F_true);
+            }
+          }
+        }
+      }
       else {
         flockfile(data->main->output.to.stream);
 
         for (i = 0; i < ranges->used; ++i) {
 
+          if (!((++data->main->signal_check) % iki_read_signal_check_d)) {
+            if (fll_program_standard_signal_received(data->main)) {
+              funlockfile(data->main->output.to.stream);
+
+              iki_read_print_signal_received(data);
+
+              status = F_status_set_error(F_interrupt);
+
+              break;
+            }
+
+            data->main->signal_check = 0;
+          }
+
           // The variable parts, when not using --wrap, each is represented on its own line.
           if (data->main->parameters.array[iki_read_parameter_line_e].result == f_console_result_additional_e) {
             if (i < data->line) continue;
@@ -338,6 +644,8 @@ extern "C" {
       status = F_data_not;
     }
 
+    f_string_dynamic_resize(0, &expand);
+
     for (i = 0; i < iki_data->variable.used; ++i) {
       macro_iki_read_substitutions_t_delete_simple(reassignments[i]);
     } // for
index 502beb716d63f1e856c114f8f1526cb05bcc8a89..1e74f51cbe1ff3987f5c2e33fb0e49b8eb57aa52 100644 (file)
@@ -51,6 +51,44 @@ extern "C" {
 #endif // _di_iki_read_process_buffer_
 
 /**
+ * Process the given range at the given index for IKI read.
+ *
+ * This expands all of the appropriate Variables so that post-expansion calculations may be performed.
+ * This is particularly useful for preparing to print a single Line in Content and Literal modes.
+ *
+ * @param data
+ *   The program data.
+ * @param iki_data
+ *   The IKI data.
+ * @param ranges
+ *   The ranges containing the desired range to print as specified by index.
+ * @param replacement
+ *   A simple substitution string for substitution, substituted only if there are no matches in the substitutions.
+ * @param wrap
+ *   The wrap will prepend a string and append a string to the content for the given range at the given index.
+ *   This is only performed when substitutions has no match for the given range at the given index.
+ * @param substitutions
+ *   The substitutions associated with the variable for the given range at the given index to use for potential printing.
+ * @param reassignments
+ *   The reassignments associated with the variable for the given range at the given index to use for potential printing.
+ * @param index
+ *   The index used to identify the desired range in variable, content, and ranges.
+ * @param expand
+ *   The buffer the data is expanded into.
+ *
+ *   Must not be NULL.
+ *
+ * @return
+ *   F_none on success.
+ *   F_data_not on success, but nothing done.
+ *
+ *   Status codes (with error bit) are returned on any problem.
+ */
+#ifndef _di_iki_read_process_buffer_at_
+  extern f_status_t iki_read_process_buffer_at(iki_read_data_t * const data, const f_iki_data_t iki_data, const iki_read_substitution_t replacement, const iki_read_substitution_t wrap, const iki_read_substitutions_t substitutions, const iki_read_substitutions_t reassignments, const f_number_unsigned_t index, f_string_dynamic_t * const expand) F_attribute_visibility_internal_d;
+#endif // _di_iki_read_process_buffer_at_
+
+/**
  * Process a given buffer, printing the given range.
  *
  * @param data