]> Kevux Git Server - fll/commitdiff
Progress: FSS write programs.
authorKevin Day <thekevinday@gmail.com>
Tue, 13 Oct 2020 01:07:50 +0000 (20:07 -0500)
committerKevin Day <thekevinday@gmail.com>
Tue, 13 Oct 2020 05:04:50 +0000 (00:04 -0500)
Add prepend functionality to all write programs.
- for FSS-0000 (Basic) and FSS-0001 (Extended), this does nothing.
- for FSS-0002 (Basic List) and FSS-0003 (Extended List), this prepends the start of multi-line content with some whitespace.

Begin working on the FSS-0003 (Extended List) write functions and programs.
- At this time, the extended list write is only implemented partially.
- I will focus on the recursive aspects later.

Add the "complete" processing to the basic list content (and now extended list content) write functions.
- Includes updates to the newline handling as appropriate.

Update documentation comments.

28 files changed:
level_0/f_fss/c/fss-common.h
level_1/fl_fss/c/fss_basic.h
level_1/fl_fss/c/fss_basic_list.c
level_1/fl_fss/c/fss_basic_list.h
level_1/fl_fss/c/fss_extended.h
level_1/fl_fss/c/fss_extended_list.c
level_1/fl_fss/c/fss_extended_list.h
level_1/fl_fss/c/private-fss.c
level_1/fl_fss/c/private-fss.h
level_2/fll_fss/c/fss_basic_list.c
level_2/fll_fss/c/fss_basic_list.h
level_3/fss_basic_list_write/c/fss_basic_list_write.c
level_3/fss_basic_list_write/c/fss_basic_list_write.h
level_3/fss_basic_list_write/c/private-fss_basic_list_write.c
level_3/fss_basic_write/c/fss_basic_write.c
level_3/fss_basic_write/c/fss_basic_write.h
level_3/fss_basic_write/c/private-fss_basic_write.c
level_3/fss_extended_list_write/c/fss_extended_list_write.c [new file with mode: 0644]
level_3/fss_extended_list_write/c/fss_extended_list_write.h [new file with mode: 0644]
level_3/fss_extended_list_write/c/main.c [new file with mode: 0644]
level_3/fss_extended_list_write/c/private-fss_extended_list_write.c [new file with mode: 0644]
level_3/fss_extended_list_write/c/private-fss_extended_list_write.h [new file with mode: 0644]
level_3/fss_extended_list_write/data/build/defines [new file with mode: 0644]
level_3/fss_extended_list_write/data/build/dependencies [new file with mode: 0644]
level_3/fss_extended_list_write/data/build/settings [new file with mode: 0644]
level_3/fss_extended_write/c/fss_extended_write.c
level_3/fss_extended_write/c/fss_extended_write.h
level_3/fss_extended_write/c/private-fss_extended_write.c

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