]> Kevux Git Server - fll/commitdiff
Update: Remove old color print functions.
authorKevin Day <thekevinday@gmail.com>
Sat, 13 Nov 2021 03:13:27 +0000 (21:13 -0600)
committerKevin Day <thekevinday@gmail.com>
Sat, 13 Nov 2021 03:14:24 +0000 (21:14 -0600)
These functions are still present for migration and just in case.

Now that I am using fl_print_format() I feel there is no reason to keep and maintain this code.
Get rid of it.

15 files changed:
level_1/fl_print/c/print.c
level_1/fl_print/c/print.h
level_2/fll_print/c/print.c
level_2/fll_print/c/print.h
level_3/controller/c/private-rule_print.c
level_3/utf8/c/main.c [new file with mode: 0644]
level_3/utf8/c/private-common.c [new file with mode: 0644]
level_3/utf8/c/private-common.h [new file with mode: 0644]
level_3/utf8/c/private-utf8.c [new file with mode: 0644]
level_3/utf8/c/private-utf8.h [new file with mode: 0644]
level_3/utf8/c/utf8.c [new file with mode: 0644]
level_3/utf8/c/utf8.h [new file with mode: 0644]
level_3/utf8/data/build/defines [new file with mode: 0644]
level_3/utf8/data/build/dependencies [new file with mode: 0644]
level_3/utf8/data/build/settings [new file with mode: 0644]

index 3fbeab11360f4c3ed2ffad4a6dedd4d87fe5ef40..852955707c39e323130b253ed327a659e0cd58b7 100644 (file)
@@ -5,92 +5,6 @@
 extern "C" {
 #endif
 
-#ifndef _di_fl_print_color_
-  f_status_t fl_print_color(const f_string_static_t buffer, const f_color_set_t set, FILE *output) {
-
-    if (!buffer.used) {
-      return F_data_not;
-    }
-
-    f_status_t status = F_none;
-
-    if (set.before) {
-      status = f_print_terminated(set.before->string, output);
-      if (F_status_is_error(status)) return status;
-    }
-
-    status = f_print(buffer.string, buffer.used, output);
-
-    if (set.after) {
-
-      // attempt to always print the closing color, even on error.
-      if (F_status_is_error(status)) {
-        f_print_terminated(set.after->string, output);
-      }
-      else {
-        status = f_print_terminated(set.after->string, output);
-        if (F_status_is_error(status)) return status;
-      }
-    }
-
-    return status;
-  }
-#endif // _di_fl_print_color_
-
-#ifndef _di_fl_print_color_after_
-  f_status_t fl_print_color_after(const f_color_set_t set, FILE *output) {
-
-    if (set.after) {
-      return f_print_terminated(set.after->string, output);
-    }
-
-    return F_data_not;
-  }
-#endif // _di_fl_print_color_after_
-
-#ifndef _di_fl_print_color_before_
-  f_status_t fl_print_color_before(const f_color_set_t set, FILE *output) {
-
-    if (set.before) {
-      return f_print_terminated(set.before->string, output);
-    }
-
-    return F_data_not;
-  }
-#endif // _di_fl_print_color_before_
-
-#ifndef _di_fl_print_color_terminated_
-  f_status_t fl_print_color_terminated(const f_string_t string, const f_color_set_t set, FILE *output) {
-
-    if (!*string) {
-      return F_data_not;
-    }
-
-    f_status_t status = F_none;
-
-    if (set.before) {
-      status = f_print_terminated(set.before->string, output);
-      if (F_status_is_error(status)) return status;
-    }
-
-    status = f_print_terminated(string, output);
-
-    if (set.after) {
-
-      // attempt to always print the closing color, even on error.
-      if (F_status_is_error(status)) {
-        f_print_terminated(set.after->string, output);
-      }
-      else {
-        status = f_print_terminated(set.after->string, output);
-        if (F_status_is_error(status)) return status;
-      }
-    }
-
-    return status;
-  }
-#endif // _di_fl_print_color_terminated_
-
 #ifndef _di_fl_print_format_
   f_status_t fl_print_format(const f_string_t string, FILE *output, ...) {
     #ifndef _di_level_1_parameter_checking_
index 37b0ead92f574428f0067623be306360c24261d2..78875457050bad74911d1332c2cedb624e965a33 100644 (file)
@@ -34,108 +34,6 @@ extern "C" {
 #endif
 
 /**
- * Print the string with the given color set printed before and after as appropriate to the file stream.
- *
- * No before/after colors are printed when the string is determined to be empty.
- *
- * This print function does not use locking, be sure something like flockfile() and funlockfile() are appropriately called.
- *
- * @param buffer
- *   The string to print.
- * @param set
- *   The color set to print.
- * @param output
- *   The file stream to output to, including standard streams such as stdout and stderr.
- *
- * @return
- *   F_data_not if nothing is printed.
- *
- *   Success from: f_print().
- *
- *   Errors (with error bit) from: f_print()
- *   Errors (with error bit) from: f_print_terminated().
- *
- * @see f_print()
- * @see f_print_terminated()
- */
-#ifndef _di_fl_print_color_
-  extern f_status_t fl_print_color(const f_string_static_t buffer, const f_color_set_t set, FILE *output);
-#endif // _di_fl_print_color_
-
-/**
- * Print the "after" part of a color set to the given file stream.
- *
- * This print function does not use locking, be sure something like flockfile() and funlockfile() are appropriately called.
- *
- * @param set
- *   The color set to print.
- * @param output
- *   The file stream to output to, including standard streams such as stdout and stderr.
- *
- * @return
- *   F_data_not if nothing is printed (such as when color code is NULL).
- *
- *   Success from: f_print_terminated().
- *
- *   Errors (with error bit) from: f_print_terminated().
- *
- * @see f_print_terminated()
- */
-#ifndef _di_fl_print_color_after_
-  extern f_status_t fl_print_color_after(const f_color_set_t set, FILE *output);
-#endif // _di_fl_print_color_after_
-
-/**
- * Print the "after" part of a color set to the given file stream.
- *
- * This print function does not use locking, be sure something like flockfile() and funlockfile() are appropriately called.
- *
- * @param set
- *   The color set to print.
- * @param output
- *   The file stream to output to, including standard streams such as stdout and stderr.
- *
- * @return
- *   F_data_not if nothing is printed (such as when color code is NULL).
- *
- *   Success from: f_print_terminated().
- *
- *   Errors (with error bit) from: f_print_terminated().
- *
- * @see f_print_terminated()
- */
-#ifndef _di_fl_print_color_before_
-  extern f_status_t fl_print_color_before(const f_color_set_t set, FILE *output);
-#endif // _di_fl_print_color_before_
-
-/**
- * Print the NULL-terminated string with the given color set printed before and after as appropriate to the file stream.
- *
- * No before/after colors are printed when the string is determined to be empty.
- *
- * This print function does not use locking, be sure something like flockfile() and funlockfile() are appropriately called.
- *
- * @param string
- *   The string to print.
- * @param set
- *   The color set to print.
- * @param output
- *   The file stream to output to, including standard streams such as stdout and stderr.
- *
- * @return
- *   F_data_not if nothing is printed.
- *
- *   Success from: f_print_terminated().
- *
- *   Errors (with error bit) from: f_print_terminated().
- *
- * @see f_print_terminated()
- */
-#ifndef _di_fl_print_color_terminated_
-  extern f_status_t fl_print_color_terminated(const f_string_t string, const f_color_set_t set, FILE *output);
-#endif // _di_fl_print_color_terminated_
-
-/**
  * A formatted print function similar to (but not the same as) the c-library fprintf() function.
  *
  * This function attempts to operate as closely to how fprintf() operates, however, there are notable differences.
index e54115b0a43098a4182c45ec2b483938ee15f3ee..13b772063698f7dbbd30bc2e2dbbf77bacb5934e 100644 (file)
@@ -43,132 +43,6 @@ extern "C" {
   }
 #endif // _di_fll_print_character_safely_
 
-#ifndef _di_fll_print_color_
-  f_status_t fll_print_color(const f_string_static_t buffer, const f_color_set_t set, FILE *output) {
-
-    if (!buffer.used) {
-      return F_data_not;
-    }
-
-    f_status_t status = F_none;
-
-    flockfile(output);
-
-    if (set.before) {
-      status = f_print_terminated(set.before->string, output);
-
-      if (F_status_is_error(status)) {
-        funlockfile(output);
-
-        return status;
-      }
-    }
-
-    status = f_print(buffer.string, buffer.used, output);
-
-    if (set.after) {
-
-      // attempt to always print the closing color, even on error.
-      if (F_status_is_error(status)) {
-        f_print_terminated(set.after->string, output);
-      }
-      else {
-        status = f_print_terminated(set.after->string, output);
-
-        if (F_status_is_error(status)) {
-          funlockfile(output);
-
-          return status;
-        }
-      }
-    }
-
-    funlockfile(output);
-
-    return status;
-  }
-#endif // _di_fll_print_color_
-
-#ifndef _di_fll_print_color_after_
-  f_status_t fll_print_color_after(const f_color_set_t set, FILE *output) {
-
-    if (set.after) {
-      flockfile(output);
-
-      const f_status_t status = f_print_terminated(set.after->string, output);
-
-      funlockfile(output);
-
-      return status;
-    }
-
-    return F_data_not;
-  }
-#endif // _di_fll_print_color_after_
-
-#ifndef _di_fll_print_color_before_
-  f_status_t fll_print_color_before(const f_color_set_t set, FILE *output) {
-
-    if (set.before) {
-      flockfile(output);
-
-      const f_status_t status = f_print_terminated(set.before->string, output);
-
-      funlockfile(output);
-
-      return status;
-    }
-
-    return F_data_not;
-  }
-#endif // _di_fll_print_color_before_
-
-#ifndef _di_fll_print_color_terminated_
-  f_status_t fll_print_color_terminated(const f_string_t string, const f_color_set_t set, FILE *output) {
-
-    if (!*string) {
-      return F_data_not;
-    }
-
-    f_status_t status = F_none;
-
-    flockfile(output);
-
-    if (set.before) {
-      status = f_print_terminated(set.before->string, output);
-
-      if (F_status_is_error(status)) {
-        funlockfile(output);
-
-        return status;
-      }
-    }
-
-    status = f_print_terminated(set.before->string, output);
-
-    if (set.after) {
-
-      // attempt to always print the closing color, even on error.
-      if (F_status_is_error(status)) {
-        f_print_terminated(set.after->string, output);
-      }
-      else {
-        status = f_print_terminated(set.after->string, output);
-
-        if (F_status_is_error(status)) {
-          funlockfile(output);
-
-          return status;
-        }
-      }
-    }
-
-    funlockfile(output);
-
-    return status;
-  }
-#endif // _di_fll_print_color_terminated_
-
 #ifndef _di_fll_print_dynamic_
   f_status_t fll_print_dynamic(const f_string_static_t buffer, FILE *output) {
 
index a46b9944b65ef0cef591d04247b724ba7ff984fd..8490503f866fab9d2a02361d9de5429fafa9522c 100644 (file)
@@ -98,108 +98,6 @@ extern "C" {
 #endif // _di_fll_print_character_safely_
 
 /**
- * This is a variation of fl_print_color() that uses locking.
- *
- * @param buffer
- *   The string to print.
- * @param set
- *   The color set to print.
- * @param output
- *   The file stream to output to, including standard streams such as stdout and stderr.
- *
- * @return
- *   F_data_not if nothing is printed.
- *
- *   Success from: f_print().
- *
- *   Errors (with error bit) from: f_print()
- *   Errors (with error bit) from: f_print_terminated().
- *
- * @see f_print()
- * @see f_print_terminated()
- * @see fl_print_color()
- */
-#ifndef _di_fll_print_color_
-  extern f_status_t fll_print_color(const f_string_static_t buffer, const f_color_set_t set, FILE *output);
-#endif // _di_fll_print_color_
-
-/**
- * This is a variation of fl_print_color_after() that uses locking.
- *
- * @param set
- *   The color set.
- * @param output
- *   The file stream to output to, including standard streams such as stdout and stderr.
- *
- * @return
- *   F_data_not if nothing is printed (such as when color code is NULL).
- *   F_parameter (with error bit) if a parameter is invalid.
- *
- *   Success from: f_print_terminated().
- *
- *   Errors (with error bit) from: f_print_terminated().
- *
- * @see flockfile()
- * @see funlockfile()
- *
- * @see f_print_terminated()
- * @see fl_print_color_after()
- */
-#ifndef _di_fll_print_color_after_
-  extern f_status_t fll_print_color_after(const f_color_set_t set, FILE *output);
-#endif // _di_fll_print_color_after_
-
-/**
- * This is a variation of fl_print_color_before() that uses locking.
- *
- * @param set
- *   The color set.
- * @param output
- *   The file stream to output to, including standard streams such as stdout and stderr.
- *
- * @return
- *   F_data_not if nothing is printed (such as when color code is NULL).
- *   F_parameter (with error bit) if a parameter is invalid.
- *
- *   Success from: f_print_terminated().
- *
- *   Errors (with error bit) from: f_print_terminated().
- *
- * @see flockfile()
- * @see funlockfile()
- *
- * @see f_print_terminated()
- * @see fl_print_color_before()
- */
-#ifndef _di_fll_print_color_before_
-  extern f_status_t fll_print_color_before(const f_color_set_t set, FILE *output);
-#endif // _di_fll_print_color_before_
-
-/**
- * This is a variation of fl_print_color_terminated() that uses locking.
- *
- * @param string
- *   The string to print.
- * @param set
- *   The color set to print.
- * @param output
- *   The file stream to output to, including standard streams such as stdout and stderr.
- *
- * @return
- *   F_data_not if nothing is printed.
- *
- *   Success from: f_print_terminated().
- *
- *   Errors (with error bit) from: f_print_terminated().
- *
- * @see f_print_terminated()
- * @see fl_print_color_terminated()
- */
-#ifndef _di_fll_print_color_terminated_
-  extern f_status_t fll_print_color_terminated(const f_string_t string, const f_color_set_t set, FILE *output);
-#endif // _di_fll_print_color_terminated_
-
-/**
  * This is a variation of f_print_dynamic() that uses locking.
  *
  * @param buffer
index 07223e8686ec505ad996e01793d12ac08481c494..b9912dcc71dbd3694691d77c4772594182e9e587 100644 (file)
@@ -86,8 +86,7 @@ extern "C" {
       fl_print_format("%[%S%]", print->to.stream, print->notable, name, print->notable);
 
       if (status == F_control_group || status == F_limit || status == F_processor || status == F_schedule) {
-        fl_print_format("%[' failed due to a failure to setup the '%]", print->to.stream, print->context, print->context);
-        fl_print_color_before(print->notable, print->to.stream);
+        fl_print_format("%[' failed due to a failure to setup the '%]%[", print->to.stream, print->context, print->context, print->notable);
 
         if (status == F_control_group) {
           f_print_terminated(controller_control_group_s, print->to.stream);
@@ -102,8 +101,7 @@ extern "C" {
           f_print_terminated(controller_scheduler_s, print->to.stream);
         }
 
-        fl_print_color_after(print->notable, print->to.stream);
-        fl_print_format("%['.%]%c", print->to.stream, print->context, print->context, f_string_eol_s[0]);
+        fl_print_format("%]%['.%]%c", print->to.stream, print->notable, print->context, print->context, f_string_eol_s[0]);
       }
       else if (WIFEXITED(process->result) ? WEXITSTATUS(process->result) : 0) {
         const uint8_t code = WIFEXITED(process->result) ? WEXITSTATUS(process->result) : 0;
diff --git a/level_3/utf8/c/main.c b/level_3/utf8/c/main.c
new file mode 100644 (file)
index 0000000..5c91bb9
--- /dev/null
@@ -0,0 +1,53 @@
+#include "utf8.h"
+
+int main(const int argc, const f_string_t *argv) {
+
+  const f_console_arguments_t arguments = { argc, argv };
+  utf8_main_t data = utf8_main_t_initialize;
+
+  if (f_pipe_input_exists()) {
+    data.process_pipe = F_true;
+  }
+
+  // Handle signals so that program can cleanly exit, deallocating as appropriate.
+  {
+    f_signal_set_empty(&data.signal.set);
+    f_signal_set_add(F_signal_abort, &data.signal.set);
+    f_signal_set_add(F_signal_broken_pipe, &data.signal.set);
+    f_signal_set_add(F_signal_hangup, &data.signal.set);
+    f_signal_set_add(F_signal_interrupt, &data.signal.set);
+    f_signal_set_add(F_signal_quit, &data.signal.set);
+    f_signal_set_add(F_signal_termination, &data.signal.set);
+
+    f_status_t status = f_signal_mask(SIG_BLOCK, &data.signal.set, 0);
+
+    if (F_status_is_error_not(status)) {
+      status = f_signal_open(&data.signal);
+
+      // If there is an error opening a signal descriptor, then do not handle signals.
+      if (F_status_is_error(status)) {
+        f_signal_mask(SIG_UNBLOCK, &data.signal.set, 0);
+        f_signal_close(&data.signal);
+      }
+    }
+  }
+
+  const f_status_t status = utf8_main(&data, &arguments);
+
+  // Flush output pipes before closing.
+  fflush(F_type_output_d);
+  fflush(F_type_error_d);
+
+  // Close all open file descriptors.
+  close(F_type_descriptor_output_d);
+  close(F_type_descriptor_input_d);
+  close(F_type_descriptor_error_d);
+
+  f_signal_close(&data.signal);
+
+  if (F_status_is_error(status) || status == F_false) {
+    return 1;
+  }
+
+  return 0;
+}
diff --git a/level_3/utf8/c/private-common.c b/level_3/utf8/c/private-common.c
new file mode 100644 (file)
index 0000000..b625b78
--- /dev/null
@@ -0,0 +1,177 @@
+#include "utf8.h"
+#include "private-common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_utf8_print_error_no_from_
+  void utf8_print_error_no_from(utf8_main_t * const main) {
+
+    if (main->error.verbosity == f_console_verbosity_quiet) return;
+
+    fll_print_format("%c%[%sNo from sources are specified, please pipe data, designate a file, or add parameters.%]%c", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context, f_string_eol_s[0]);
+  }
+#endif // _di_utf8_print_error_no_from_
+
+#ifndef _di_utf8_print_error_no_value_
+  void utf8_print_error_no_value(utf8_main_t * const main, const f_string_t parameter) {
+
+    if (main->error.verbosity == f_console_verbosity_quiet) return;
+
+    flockfile(main->error.to.stream);
+
+    fl_print_format("%c%[%SThe parameter '%]", main->error.to.stream, f_string_eol_s[0], main->context.set.error, main->error.prefix, main->context.set.error);
+    fl_print_format("%[%s%S%]", main->error.to.stream, main->context.set.notable, f_console_symbol_long_enable_s, parameter, main->context.set.notable);
+    fl_print_format("%[' is specified, but no value was given.%]%c", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s[0]);
+
+    funlockfile(main->error.to.stream);
+  }
+#endif // _di_utf8_print_error_no_value_
+
+#ifndef _di_utf8_print_error_parameter_conflict_
+  void utf8_print_error_parameter_conflict(utf8_main_t * const main, const f_string_t first, const f_string_t second) {
+
+    if (main->error.verbosity == f_console_verbosity_quiet) return;
+
+    flockfile(main->output.to.stream);
+
+    fl_print_format("%c%[%sThe parameter '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix, main->error.context);
+    fl_print_format("%[%s%S%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, first, main->error.notable);
+    fl_print_format("%[' cannot be used with the parameter '%]", main->error.to.stream, main->error.context, main->error.context);
+    fl_print_format("%[%s%S%]", main->error.to.stream, main->error.notable, f_console_symbol_long_enable_s, second, main->error.notable);
+    fl_print_format("%['.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]);
+
+    funlockfile(main->output.to.stream);
+  }
+#endif // _di_utf8_print_error_parameter_conflict_
+
+#ifndef _di_utf8_print_error_parameter_file_name_empty_
+  void utf8_print_error_parameter_file_name_empty(utf8_main_t * const main, const f_array_length_t index) {
+
+    if (main->error.verbosity == f_console_verbosity_quiet) return;
+
+    flockfile(main->error.to.stream);
+
+    fl_print_format("%c%[%SNo file specified at parameter index %]", main->error.to.stream, f_string_eol_s[0], main->context.set.error, main->error.prefix, main->context.set.error);
+    fl_print_format("%[%ul%]", main->error.to.stream, main->context.set.notable, index, main->context.set.notable);
+    fl_print_format("%[.%]%c", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s[0]);
+
+    funlockfile(main->error.to.stream);
+  }
+#endif // _di_utf8_print_error_parameter_file_name_empty_
+
+#ifndef _di_utf8_print_error_parameter_file_not_found_
+  void utf8_print_error_parameter_file_not_found(utf8_main_t * const main, const bool from, const f_string_t name) {
+
+    if (main->error.verbosity == f_console_verbosity_quiet) return;
+
+    flockfile(main->error.to.stream);
+
+    fl_print_format("%c%[%SFailed to find the %s file '%]", main->error.to.stream, f_string_eol_s[0], main->context.set.error, main->error.prefix, from ? utf8_string_from_s : utf8_string_to_s, main->context.set.error);
+    fl_print_format("%[%S%]", main->error.to.stream, main->context.set.notable, name, main->context.set.notable);
+    fl_print_format("%['.%]%c", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s[0]);
+
+    funlockfile(main->error.to.stream);
+  }
+#endif // _di_utf8_print_error_parameter_file_not_found_
+
+#ifndef _di_utf8_print_error_parameter_file_to_too_many_
+  void utf8_print_error_parameter_file_to_too_many(utf8_main_t * const main) {
+
+    if (main->error.verbosity == f_console_verbosity_quiet) return;
+
+    fll_print_format("%c%[%SToo many %s files specified, there may only be one to file.%]%c", main->error.to.stream, f_string_eol_s[0], main->context.set.error, main->error.prefix, utf8_string_to_s, main->context.set.error, f_string_eol_s[0]);
+  }
+#endif // _di_utf8_print_error_parameter_file_to_too_many_
+
+#ifndef _di_utf8_print_section_header_file_
+  void utf8_print_section_header_file(utf8_main_t * const main, const f_string_t name) {
+
+    if (main->output.verbosity == f_console_verbosity_quiet) return;
+    if (main->parameters[utf8_parameter_headers].result == f_console_result_none) return;
+
+    flockfile(main->output.to.stream);
+
+    fl_print_format("%c%[File%] ", main->output.to.stream, f_string_eol_s[0], main->output.set->title, main->output.set->title);
+    fl_print_format("%[%S%]:%c", main->output.to.stream, main->output.set->notable, name, main->output.set->notable, f_string_eol_s[0]);
+
+    funlockfile(main->output.to.stream);
+  }
+#endif // _di_utf8_print_section_header_file_
+
+#ifndef _di_utf8_print_section_header_parameter_
+  void utf8_print_section_header_parameter(utf8_main_t * const main, const f_array_length_t index) {
+
+    if (main->output.verbosity == f_console_verbosity_quiet) return;
+    if (main->parameters[utf8_parameter_headers].result == f_console_result_none) return;
+
+    flockfile(main->output.to.stream);
+
+    fl_print_format("%c%[Parameter%] ", main->output.to.stream, f_string_eol_s[0], main->output.set->title, main->output.set->title);
+    fl_print_format("%[%ul%]:%c", main->output.to.stream, main->output.set->notable, index, main->output.set->notable, f_string_eol_s[0]);
+
+    funlockfile(main->output.to.stream);
+  }
+#endif // _di_utf8_print_section_header_parameter_
+
+#ifndef _di_utf8_print_section_header_pipe_
+  void utf8_print_section_header_pipe(utf8_main_t * const main) {
+
+    if (main->output.verbosity == f_console_verbosity_quiet) return;
+    if (main->parameters[utf8_parameter_headers].result == f_console_result_none) return;
+
+    fll_print_format("%c%[Pipe%]:%c", main->output.to.stream, f_string_eol_s[0], main->output.set->title, main->output.set->title, f_string_eol_s[0]);
+  }
+#endif // _di_utf8_print_section_header_pipe_
+
+#ifndef _di_utf8_print_signal_received_
+  void utf8_print_signal_received(utf8_main_t * const main, const f_status_t signal) {
+
+    if (main->warning.verbosity != f_console_verbosity_verbose) return;
+
+    // Must flush and reset color because the interrupt may have interrupted the middle of a print function.
+    fflush(main->warning.to.stream);
+
+    flockfile(main->warning.to.stream);
+
+    fl_print_format("%]%c%c%[Received signal code %]", main->warning.to.stream, main->context.set.reset, f_string_eol_s[0], f_string_eol_s[0], main->context.set.warning, main->context.set.warning);
+    fl_print_format("%[%i%]", main->warning.to.stream, main->context.set.notable, signal, main->context.set.notable);
+    fl_print_format("%[.%]%c", main->warning.to.stream, main->context.set.warning, main->context.set.warning, f_string_eol_s[0]);
+
+    funlockfile(main->warning.to.stream);
+  }
+#endif // _di_utf8_print_signal_received_
+
+#ifndef _di_utf8_signal_received_
+  f_status_t utf8_signal_received(utf8_main_t * const main) {
+
+    if (!main->signal.id) {
+      return F_false;
+    }
+
+    struct signalfd_siginfo information;
+
+    memset(&information, 0, sizeof(struct signalfd_siginfo));
+
+    if (f_signal_read(main->signal, 0, &information) == F_signal) {
+      switch (information.ssi_signo) {
+        case F_signal_abort:
+        case F_signal_broken_pipe:
+        case F_signal_hangup:
+        case F_signal_interrupt:
+        case F_signal_quit:
+        case F_signal_termination:
+          utf8_print_signal_received(main, information.ssi_signo);
+
+          return information.ssi_signo;
+      }
+    }
+
+    return F_false;
+  }
+#endif // _di_utf8_signal_received_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_3/utf8/c/private-common.h b/level_3/utf8/c/private-common.h
new file mode 100644 (file)
index 0000000..b7f40ca
--- /dev/null
@@ -0,0 +1,138 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: UTF-8
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ */
+#ifndef _PRIVATE_common_h
+#define _PRIVATE_common_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Print error message for when no sources are provided.
+ *
+ * @param main
+ *   The main program data.
+ */
+#ifndef _di_utf8_print_error_no_from_
+  extern void utf8_print_error_no_from(utf8_main_t * const main) F_attribute_visibility_internal_d;
+#endif // _di_utf8_print_error_no_from_
+
+/**
+ * Print error message for when no sources are provided.
+ *
+ * @param main
+ *   The main program data.
+ * @param parameter_1
+ *   The long parameter name.
+ */
+#ifndef _di_utf8_print_error_no_value_
+  extern void utf8_print_error_no_value(utf8_main_t * const main, const f_string_t parameter) F_attribute_visibility_internal_d;
+#endif // _di_utf8_print_error_no_value_
+
+/**
+ * Print error message for two parameters not being allowed to be used together.
+ *
+ * @param main
+ *   The main program data.
+ * @param first
+ *   The long parameter name for the first parameter.
+ * @param second
+ *   The long parameter name for the second parameter.
+ */
+#ifndef _di_utf8_print_error_parameter_conflict_
+  extern void utf8_print_error_parameter_conflict(utf8_main_t * const main, const f_string_t first, const f_string_t second) F_attribute_visibility_internal_d;
+#endif // _di_utf8_print_error_parameter_conflict_
+
+/**
+ * Print error message for when the file parameter is an empty string.
+ *
+ * @param main
+ *   The main program data.
+ * @param index
+ *   The index within the argv[] array where the empty string is found.
+ */
+#ifndef _di_utf8_print_error_parameter_file_name_empty_
+  extern void utf8_print_error_parameter_file_name_empty(utf8_main_t * const main, const f_array_length_t index) F_attribute_visibility_internal_d;
+#endif // _di_utf8_print_error_parameter_file_name_empty_
+
+/**
+ * Print error message for when no sources are provided in the main program parameters.
+ *
+ * @param main
+ *   The main program data.
+ * @param from
+ *   If TRUE, then this is a from file (source file).
+ *   If FALSE, then this is a to file (destination file).
+ * @param name
+ *   The file path name.
+ */
+#ifndef _di_utf8_print_error_parameter_file_not_found_
+  extern void utf8_print_error_parameter_file_not_found(utf8_main_t * const main, const bool from, const f_string_t name) F_attribute_visibility_internal_d;
+#endif // _di_utf8_print_error_parameter_file_not_found_
+
+/**
+ * Print error message for when too many 'to' destinations are specified.
+ *
+ * @param main
+ *   The main program data.
+ */
+#ifndef _di_utf8_print_error_parameter_file_to_too_many_
+  extern void utf8_print_error_parameter_file_to_too_many(utf8_main_t * const main) F_attribute_visibility_internal_d;
+#endif // _di_utf8_print_error_parameter_file_to_too_many_
+
+/**
+ * Print the input file section header.
+ *
+ * @param main
+ *   The main program data.
+ * @param name
+ *   The name of the file.
+ */
+#ifndef _di_utf8_print_section_header_file_
+  extern void utf8_print_section_header_file(utf8_main_t * const main, const f_string_t name) F_attribute_visibility_internal_d;
+#endif // _di_utf8_print_section_header_file_
+
+/**
+ * Print the input parameter section header.
+ *
+ * @param main
+ *   The main program data.
+ * @param index
+ *   The index position of the parameter.
+ */
+#ifndef _di_utf8_print_section_header_parameter_
+  extern void utf8_print_section_header_parameter(utf8_main_t * const main, const f_array_length_t index) F_attribute_visibility_internal_d;
+#endif // _di_utf8_print_section_header_parameter_
+
+/**
+ * Print the input pipe section header.
+ *
+ * @param main
+ *   The main program data.
+ */
+#ifndef _di_utf8_print_section_header_pipe_
+  extern void utf8_print_section_header_pipe(utf8_main_t * const main) F_attribute_visibility_internal_d;
+#endif // _di_utf8_print_section_header_pipe_
+
+/**
+ * Print a message about a process signal being recieved, such as an interrupt signal.
+ *
+ * @param main
+ *   The main program data.
+ * @param signal
+ *   The signal code received.
+ */
+#ifndef _di_utf8_print_signal_received_
+  extern void utf8_print_signal_received(utf8_main_t * const main, const f_status_t signal) F_attribute_visibility_internal_d;
+#endif // _di_utf8_print_signal_received_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_common_h
diff --git a/level_3/utf8/c/private-utf8.c b/level_3/utf8/c/private-utf8.c
new file mode 100644 (file)
index 0000000..7689cde
--- /dev/null
@@ -0,0 +1,400 @@
+#include "utf8.h"
+#include "private-common.h"
+#include "private-utf8.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_utf8_convert_binary_
+  f_status_t utf8_convert_binary(utf8_main_t * const main, const f_string_static_t character) {
+
+    f_status_t status = F_none;
+
+    f_string_t prepend = "";
+    f_string_t append = "";
+    f_color_set_t error = f_color_set_t_initialize;
+
+    if (main->mode & utf8_mode_to_codepoint_d) {
+      if (main->parameters[utf8_parameter_verify].result == f_console_result_found) {
+        if (main->parameters[utf8_parameter_headers].result == f_console_result_found) {
+          prepend = "  ";
+        }
+        else {
+          prepend = " ";
+        }
+
+        append = f_string_eol_s;
+      }
+      else {
+        error = main->output.set->error;
+        prepend = " ";
+      }
+    }
+
+    uint32_t codepoint = 0;
+
+    if (character.used) {
+      status = f_utf_unicode_to(character.string, character.used, &codepoint);
+    }
+    else {
+      status = F_status_set_error(F_utf);
+    }
+
+    if (F_status_is_error(status)) {
+      if (F_status_set_fine(status) == F_failure || F_status_set_fine(status) == F_utf) {
+        if (main->parameters[utf8_parameter_strip_invalid].result == f_console_result_none) {
+          if (main->mode & utf8_mode_to_binary_d) {
+            fl_print_format("%s%[", main->output.to.stream, prepend, error);
+
+            for (f_array_length_t i = 0; i < character.used; ++i) {
+              f_print_character(character.string[i], main->output.to.stream);
+            } // for
+
+            fl_print_format("%s%[", main->output.to.stream, error, append);
+          }
+          else {
+            fl_print_format("%s%[0x", main->output.to.stream, prepend, error);
+
+            for (uint8_t i = 0; i < character.used; ++i) {
+              fl_print_format("%02_uii", main->output.to.stream, (uint8_t) character.string[i]);
+            } // for
+
+            fl_print_format("%]%s", main->output.to.stream, error, append);
+          }
+        }
+      }
+      else {
+        if (main->error.verbosity != f_console_verbosity_quiet) {
+          fl_print_format("%c%[%SFailed to decode character '%]", main->error.to.stream, f_string_eol_s[0], main->context.set.error, main->context.set.error);
+          fl_print_format("%[%r%]", main->error.to.stream, main->context.set.notable, character, main->context.set.notable);
+          fl_print_format("%[', error status code%] ", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s[0]);
+          fl_print_format("%[%S%]", main->error.to.stream, main->context.set.notable, F_status_set_fine(status), main->context.set.notable);
+          fl_print_format("%[.%]%c", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s[0]);
+        }
+
+        return status;
+      }
+    }
+    else if (main->parameters[utf8_parameter_verify].result == f_console_result_none) {
+      if (main->mode & utf8_mode_to_binary_d) {
+        f_print_terminated(prepend, main->output.to.stream);
+
+        for (f_array_length_t i = 0; i < character.used; ++i) {
+          f_print_character(character.string[i], main->output.to.stream);
+        } // for
+
+        f_print_terminated(append, main->output.to.stream);
+      }
+      else {
+        if (character.used < 4) {
+          fl_print_format("%sU+%04_U%s", main->output.to.stream, prepend, codepoint, append);
+        }
+        else {
+          fl_print_format("%sU+%06_U%s", main->output.to.stream, prepend, codepoint, append);
+        }
+      }
+    }
+
+    if (F_status_is_error(status)) {
+      return F_utf;
+    }
+
+    return F_none;
+  }
+#endif // _di_utf8_convert_binary_
+
+#ifndef _di_utf8_convert_codepoint_
+  f_status_t utf8_convert_codepoint(utf8_main_t * const main, const f_string_static_t character, uint8_t *mode) {
+
+    f_status_t status = F_none;
+
+    // @todo
+
+
+    return F_none;
+  }
+#endif // _di_utf8_convert_codepoint_
+
+#ifndef _di_utf8_process_file_binary_
+  f_status_t utf8_process_file_binary(utf8_main_t * const main, const f_file_t file) {
+
+    f_status_t status = F_none;
+    bool valid = F_true;
+    bool next = F_true;
+    uint8_t mode = 0;
+
+    f_array_length_t i = 0;
+    f_array_length_t j = 0;
+
+    char block_character[4] = { 0, 0, 0, 0 };
+    f_string_static_t character = macro_f_string_static_t_initialize(block_character, 4);
+
+    do {
+      status = f_file_read_block(file, &main->buffer);
+
+      if (status == F_none_eof && !main->buffer.used) break;
+
+      for (i = 0; F_status_is_fine(status) && i < main->buffer.used; ) {
+
+        status = utf8_signal_received(main);
+
+        if (status) {
+          utf8_print_signal_received(main, status);
+
+          status = F_status_set_error(F_signal);
+          break;
+        }
+        else {
+          status = F_none;
+        }
+
+        // Get the current width only when processing a new block.
+        if (next) {
+          character.used = macro_f_utf_byte_width(main->buffer.string[i]);
+          next = F_false;
+        }
+
+        for (; j < character.used && i < main->buffer.used; ++j, ++i) {
+          character.string[j] = main->buffer.string[i];
+        } // for
+
+        if (j == character.used) {
+          if (main->mode & utf8_mode_from_binary_d) {
+            status = utf8_convert_binary(main, character);
+          }
+          else {
+            // @todo: check character and determine status.
+            /*private_utf8_codepoint_modes_ready = 1,
+            private_utf8_codepoint_modes_begin,
+            private_utf8_codepoint_modes_number,
+            private_utf8_codepoint_modes_end,
+            private_utf8_codepoint_modes_bad,*/
+            status = utf8_convert_codepoint(main, character, &mode);
+          }
+
+          if (status == F_utf) {
+            valid = F_false;
+          }
+
+          j = 0;
+          next = F_true;
+        }
+      } // for
+
+      i = 0;
+      main->buffer.used = 0;
+
+    } while (F_status_is_fine(status) && status != F_signal);
+
+    // Handle last (incomplete) character when the buffer ended before the character is supposed to end.
+    if (status != F_signal && next == F_false) {
+      character.used = j;
+
+      if (main->mode & utf8_mode_from_binary_d) {
+        status = utf8_convert_binary(main, character);
+      }
+      else {
+        // @todo: check character and determine status.
+        /*private_utf8_codepoint_modes_ready = 1,
+        private_utf8_codepoint_modes_begin,
+        private_utf8_codepoint_modes_number,
+        private_utf8_codepoint_modes_end,
+        private_utf8_codepoint_modes_bad,*/
+        status = utf8_convert_codepoint(main, character, &mode);
+      }
+
+      if (status == F_utf) {
+        valid = F_false;
+      }
+    }
+
+    main->buffer.used = 0;
+
+    if (F_status_is_error(status)) {
+      return status;
+    }
+
+    return valid;
+  }
+#endif // _di_utf8_process_file_binary_
+
+#ifndef _di_utf8_process_file_codepoint_
+  f_status_t utf8_process_file_codepoint(utf8_main_t * const main, const f_file_t file) {
+
+    f_status_t status = F_none;
+    bool valid = F_true;
+    bool next = F_true;
+
+    f_array_length_t i = 0;
+    f_array_length_t j = 0;
+
+    char block[4] = { 0, 0, 0, 0 };
+    f_string_static_t character = macro_f_string_static_t_initialize(block, 4);
+
+    do {
+      status = f_file_read_block(file, &main->buffer);
+
+      if (status == F_none_eof && !main->buffer.used) break;
+
+      for (i = 0; F_status_is_fine(status) && i < main->buffer.used; ) {
+
+        status = utf8_signal_received(main);
+
+        if (status) {
+          utf8_print_signal_received(main, status);
+
+          status = F_status_set_error(F_signal);
+          break;
+        }
+        else {
+          status = F_none;
+        }
+
+        // Get the current width only when processing a new block.
+        if (next) {
+          character.used = macro_f_utf_byte_width(main->buffer.string[i]);
+          next = F_false;
+        }
+
+        for (; j < character.used && i < main->buffer.used; ++j, ++i) {
+          character.string[j] = main->buffer.string[i];
+        } // for
+
+        if (j == character.used) {
+          status = utf8_convert_binary(main, character);
+
+          if (status == F_utf) {
+            valid = F_false;
+          }
+
+          j = 0;
+          next = F_true;
+        }
+      } // for
+
+      i = 0;
+      main->buffer.used = 0;
+
+    } while (F_status_is_fine(status) && status != F_signal);
+
+    // Handle last (incomplete) character when the buffer ended before the character is supposed to end.
+    if (status != F_signal && next == F_false) {
+      character.used = j;
+
+      status = utf8_convert_binary(main, character);
+
+      if (status == F_utf) {
+        valid = F_false;
+      }
+    }
+
+    main->buffer.used = 0;
+
+    if (F_status_is_error(status)) {
+      return status;
+    }
+
+    return valid;
+  }
+#endif // _di_utf8_process_file_codepoint_
+
+#ifndef _di_utf8_process_text_
+  f_status_t utf8_process_text(utf8_main_t * const main, const f_string_t text) {
+
+    if (!text) {
+      return F_true;
+    }
+
+    f_status_t status = F_none;
+    bool valid = F_true;
+    uint8_t mode = 0;
+
+    f_string_static_t character = macro_f_string_static_t_initialize(text, 4);
+
+    flockfile(main->output.to.stream);
+
+    while (*character.string && F_status_is_error_not(status)) {
+
+      status = utf8_signal_received(main);
+
+      if (status) {
+        utf8_print_signal_received(main, status);
+
+        status = F_status_set_error(F_signal);
+        break;
+      }
+      else {
+        status = F_none;
+      }
+
+      character.used = macro_f_utf_byte_width(*character.string);
+
+      // Re-adjust used if buffer ended before the character is supposed to end.
+      if (character.string[0]) {
+        if (character.used > 1) {
+          if (character.string[1]) {
+            if (character.used > 2) {
+              if (character.string[2]) {
+                if (character.used > 3) {
+                  if (character.string[3]) {
+                    character.used = 4;
+                  }
+                  else {
+                    character.used = 3;
+                  }
+                }
+              }
+              else {
+                character.used = 2;
+              }
+            }
+          }
+          else {
+            character.used = 1;
+          }
+        }
+      }
+      else {
+        character.used = 0;
+      }
+
+      if (main->mode & utf8_mode_from_binary_d) {
+        status = utf8_convert_binary(main, character);
+      }
+      else {
+        // @todo: check character and determine status.
+        /*private_utf8_codepoint_modes_ready = 1,
+        private_utf8_codepoint_modes_begin,
+        private_utf8_codepoint_modes_number,
+        private_utf8_codepoint_modes_end,
+        private_utf8_codepoint_modes_bad,*/
+        status = utf8_convert_codepoint(main, character, &mode);
+      }
+
+      character.string += character.used;
+
+      if (status == F_utf) {
+        valid = F_false;
+      }
+    } // while
+
+    if (F_status_is_error(status)) {
+      funlockfile(main->output.to.stream);
+
+      return status;
+    }
+
+    if (main->parameters[utf8_parameter_verify].result == f_console_result_none) {
+      f_print_character(f_string_eol_s[0], main->output.to.stream);
+    }
+
+    funlockfile(main->output.to.stream);
+
+    return valid;
+  }
+#endif // _di_utf8_process_text_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_3/utf8/c/private-utf8.h b/level_3/utf8/c/private-utf8.h
new file mode 100644 (file)
index 0000000..7c48eeb
--- /dev/null
@@ -0,0 +1,179 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: UTF-8
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ */
+#ifndef _PRIVATE_utf8_h
+#define _PRIVATE_utf8_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @todo make this a define rather than an enum so that "bad/invalid" can be passed along with different state values.
+ *       Or do some sort of trick ("XXX >> 1, to get enum value such that the first bit represents valid/invalid).
+ * private_utf8_codepoint_modes_*:
+ *   - ready:  The codepoint has yet to be processed, skip leading spaces until first 'U' is matched.
+ *   - begin:  The first 'U' is matched, look for the '+'.
+ *   - number: The '+' is matched, process numbers.
+ *   - end:    The last number is reached (at either whitespace or EOS/EOF).
+ *   - bad:    This is not a valid codepoint.
+ */
+#ifndef _di_private_utf8_codepoint_modes_
+  enum {
+    private_utf8_codepoint_modes_ready = 1,
+    private_utf8_codepoint_modes_begin,
+    private_utf8_codepoint_modes_number,
+    private_utf8_codepoint_modes_end,
+    private_utf8_codepoint_modes_bad,
+  };
+#endif // _di_private_utf8_codepoint_modes_
+
+/**
+ * Convert a binary character to another format.
+ *
+ * This automatically determines the output format and is also handles the verify process.
+ *
+ * @param main
+ *   The main program data.
+ * @param character
+ *   The a single character to convert.
+ *   This does not stop on NULL and will process all text until text.used.
+ *
+ * @return
+ *   F_none on success.
+ *   F_utf on invalid UTF-8 (which is still "success" when verifying).
+ *
+ *   F_utf (with error bit) if not verifying and
+ *
+ *   Errors (with error bit) from: f_utf_unicode_to()
+ */
+#ifndef _di_utf8_convert_binary_
+  extern f_status_t utf8_convert_binary(utf8_main_t * const main, const f_string_static_t character) F_attribute_visibility_internal_d;
+#endif // _di_utf8_convert_binary_
+
+/**
+ * Convert a codepoint character representation to another format.
+ *
+ * This automatically determines the output format and is also handles the verify process.
+ *
+ * @param main
+ *   The main program data.
+ * @param character
+ *   The a single character to convert.
+ *   This does not stop on NULL and will process all text until text.used.
+ * @param mode
+ *   Designate the mode in which the curent state is being processed.
+ *
+ * @return
+ *   F_none on success.
+ *   F_utf on invalid UTF-8 (which is still "success" when verifying).
+ *
+ *   F_utf (with error bit) if not verifying and
+ *
+ *   Errors (with error bit) from: f_utf_unicode_to()
+ */
+#ifndef _di_utf8_convert_codepoint_
+  extern f_status_t utf8_convert_codepoint(utf8_main_t * const main, const f_string_static_t text, uint8_t *mode) F_attribute_visibility_internal_d;
+#endif // _di_utf8_convert_codepoint_
+
+/**
+ * Process file as a binary input, handling conversion or verification as appropriate.
+ *
+ * @param main
+ *   The main program data.
+ * @param file
+ *   The file stream to process.
+ *   This file may contain NULLs.
+ *
+ * @return
+ *   F_true on success and is valid.
+ *   F_false on success and contains invalid sequences.
+ *   F_signal on (exit) signal received.
+ *
+ *   Errors (with error bit) from: utf8_convert_binary()
+ *   Errors (with error bit) from: utf8_convert_codepoint()
+ *
+ * @see utf8_convert_binary()
+ * @see utf8_signal_received()
+ */
+#ifndef _di_utf8_process_file_binary_
+  extern f_status_t utf8_process_file_binary(utf8_main_t * const main, const f_file_t file) F_attribute_visibility_internal_d;
+#endif // _di_utf8_process_file_binary_
+
+/**
+ * Process file as a codepoint input, handling conversion or verification as appropriate.
+ *
+ * @param main
+ *   The main program data.
+ * @param file
+ *   The file stream to process.
+ *   This file may contain NULLs.
+ *
+ * @return
+ *   F_true on success and is valid.
+ *   F_false on success and contains invalid sequences.
+ *   F_signal on (exit) signal received.
+ *
+ *   Errors (with error bit) from: utf8_convert_binary()
+ *   Errors (with error bit) from: utf8_convert_codepoint()
+ *
+ * @see utf8_convert_binary()
+ * @see utf8_convert_codepoint()
+ * @see utf8_signal_received()
+ */
+#ifndef _di_utf8_process_file_codepoint_
+  extern f_status_t utf8_process_file_codepoint(utf8_main_t * const main, const f_file_t file) F_attribute_visibility_internal_d;
+#endif // _di_utf8_process_file_codepoint_
+
+/**
+ * Convert the text from one format to other another format or verify text.
+ *
+ * @param main
+ *   The main program data.
+ * @param text
+ *   This represent a single text data.
+ *   This text is NULL terminated and can therefore not contain any NULLs.
+ *
+ * @return
+ *   F_true on success and is valid.
+ *   F_false on success and contains invalid sequences.
+ *   F_signal on (exit) signal received.
+ *
+ *   Errors (with error bit) from: utf8_convert_binary()
+ *   Errors (with error bit) from: utf8_convert_codepoint()
+ *
+ * @see utf8_convert_binary()
+ * @see utf8_convert_codepoint()
+ * @see utf8_signal_received()
+ */
+#ifndef _di_utf8_process_text_
+  extern f_status_t utf8_process_text(utf8_main_t * const main, const f_string_t text) F_attribute_visibility_internal_d;
+#endif // _di_utf8_process_text_
+
+/**
+ * Check to see if a process signal is received.
+ *
+ * Only signals that are blocked via main.signal will be received.
+ *
+ * @param main
+ *   The main program data.
+ *
+ * @return
+ *   A positive number representing a valid signal on signal received.
+ *   F_false on no signal received.
+ *
+ * @see f_signal_read()
+ */
+#ifndef _di_utf8_signal_received_
+  extern f_status_t utf8_signal_received(utf8_main_t * const main);
+#endif // _di_utf8_signal_received_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_utf8_h
diff --git a/level_3/utf8/c/utf8.c b/level_3/utf8/c/utf8.c
new file mode 100644 (file)
index 0000000..7839c0f
--- /dev/null
@@ -0,0 +1,470 @@
+#include "utf8.h"
+#include "private-common.h"
+#include "private-utf8.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_utf8_print_help_
+  f_status_t utf8_print_help(const f_file_t file, const f_color_context_t context) {
+
+    flockfile(file.stream);
+
+    fll_program_print_help_header(file, context, utf8_program_name_long_s, utf8_version_s);
+
+    fll_program_print_help_option(file, context, f_console_standard_short_help_s, f_console_standard_long_help_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, "    Print this help message.");
+    fll_program_print_help_option(file, context, f_console_standard_short_dark_s, f_console_standard_long_dark_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, "    Output using colors that show up better on dark backgrounds.");
+    fll_program_print_help_option(file, context, f_console_standard_short_light_s, f_console_standard_long_light_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, "   Output using colors that show up better on light backgrounds.");
+    fll_program_print_help_option(file, context, f_console_standard_short_no_color_s, f_console_standard_long_no_color_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, "Do not file in color.");
+    fll_program_print_help_option(file, context, f_console_standard_short_quiet_s, f_console_standard_long_quiet_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, "   Decrease verbosity, silencing most output.");
+    fll_program_print_help_option(file, context, f_console_standard_short_normal_s, f_console_standard_long_normal_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, "  Set verbosity to normal file.");
+    fll_program_print_help_option(file, context, f_console_standard_short_verbose_s, f_console_standard_long_verbose_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Increase verbosity beyond normal output.");
+    fll_program_print_help_option(file, context, f_console_standard_short_debug_s, f_console_standard_long_debug_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, "   Enable debugging, significantly increasing verbosity beyond normal output.");
+    fll_program_print_help_option(file, context, f_console_standard_short_version_s, f_console_standard_long_version_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Print only the version number.");
+
+    f_print_character(f_string_eol_s[0], file.stream);
+
+    fll_program_print_help_option(file, context, utf8_short_from_binary_s, utf8_long_from_binary_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, "   The expected input format is binary (character data).");
+    fll_program_print_help_option(file, context, utf8_short_from_codepoint_s, utf8_long_from_codepoint_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, "The expected input format is codepoint (such as U+0000).");
+    fll_program_print_help_option(file, context, utf8_short_from_file_s, utf8_long_from_file_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, "     Use the given file as the input source.");
+
+    f_print_character(f_string_eol_s[0], file.stream);
+
+    fll_program_print_help_option(file, context, utf8_short_to_binary_s, utf8_long_to_binary_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, "   The output format is binary (character data).");
+    fll_program_print_help_option(file, context, utf8_short_to_codepoint_s, utf8_long_to_codepoint_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, "The output format is codepoint (such as U+0000).");
+    fll_program_print_help_option(file, context, utf8_short_to_file_s, utf8_long_to_file_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, "     Use the given file as the output destination.");
+
+    f_print_character(f_string_eol_s[0], file.stream);
+
+    fll_program_print_help_option(file, context, utf8_short_headers_s, utf8_long_headers_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, "      Print headers for each section (pipe, file, or parameter).");
+    fll_program_print_help_option(file, context, utf8_short_strip_invalid_s, utf8_long_strip_invalid_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, "Strip invalid Unicode characters.");
+    fll_program_print_help_option(file, context, utf8_short_verify_s, utf8_long_verify_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, "       Only perform verification of valid sequences.");
+
+    f_print_character(f_string_eol_s[0], file.stream);
+    f_print_character(f_string_eol_s[0], file.stream);
+
+    fll_program_print_help_usage(file, context, utf8_program_name_s, "filename(s)");
+
+    fl_print_format("  The default behavior is to assume the expected input is binary from the command line to be output to the screen as codepoints.%c%c", file.stream, f_string_eol_s[0], f_string_eol_s[0]);
+
+    fl_print_format("  Multiple input sources are allowed but only a single output destination is allowed.%c%c", file.stream, f_string_eol_s[0], f_string_eol_s[0]);
+
+    fl_print_format("  When using the parameter '%[%s%s%]', only invalid data is printed and 0 is returned if valid or 1 is returned if invalid.%c", file.stream, context.set.notable, f_console_symbol_long_enable_s, utf8_long_verify_s, context.set.notable, f_string_eol_s[0]);
+
+    funlockfile(file.stream);
+
+    return F_none;
+  }
+#endif // _di_utf8_print_help_
+
+#ifndef _di_utf8_main_
+  f_status_t utf8_main(utf8_main_t * const main, const f_console_arguments_t *arguments) {
+
+    f_status_t status = F_none;
+
+    {
+      const f_console_parameters_t parameters = macro_f_console_parameters_t_initialize(main->parameters, utf8_total_parameters_d);
+
+      // Identify priority of color parameters.
+      {
+        f_console_parameter_id_t ids[3] = { utf8_parameter_no_color, utf8_parameter_light, utf8_parameter_dark };
+        const f_console_parameter_ids_t choices = macro_f_console_parameter_ids_t_initialize(ids, 3);
+
+        status = fll_program_parameter_process(*arguments, parameters, choices, F_true, &main->remaining, &main->context);
+
+        main->output.set = &main->context.set;
+        main->error.set = &main->context.set;
+        main->warning.set = &main->context.set;
+
+        if (main->context.set.error.before) {
+          main->output.context = f_color_set_empty_s;
+          main->output.notable = main->context.set.notable;
+
+          main->error.context = main->context.set.error;
+          main->error.notable = main->context.set.notable;
+
+          main->warning.context = main->context.set.warning;
+          main->warning.notable = main->context.set.notable;
+        }
+        else {
+          f_color_set_t *sets[] = { &main->output.context, &main->output.notable, &main->error.context, &main->error.notable, &main->warning.context, &main->warning.notable, 0 };
+
+          fll_program_parameter_process_empty(&main->context, sets);
+        }
+
+        if (F_status_is_error(status)) {
+          fll_error_print(main->error, F_status_set_fine(status), "fll_program_parameter_process", F_true);
+
+          utf8_main_delete(main);
+
+          return F_status_set_error(status);
+        }
+      }
+
+      // Identify priority of verbosity related parameters.
+      {
+        f_console_parameter_id_t ids[4] = { utf8_parameter_verbosity_quiet, utf8_parameter_verbosity_normal, utf8_parameter_verbosity_verbose, utf8_parameter_verbosity_debug };
+        f_console_parameter_id_t choice = 0;
+        const f_console_parameter_ids_t choices = macro_f_console_parameter_ids_t_initialize(ids, 4);
+
+        status = f_console_parameter_prioritize_right(parameters, choices, &choice);
+
+        if (F_status_is_error(status)) {
+          fll_error_print(main->error, F_status_set_fine(status), "f_console_parameter_prioritize_right", F_true);
+
+          utf8_main_delete(main);
+
+          return status;
+        }
+
+        if (choice == utf8_parameter_verbosity_quiet) {
+          main->output.verbosity = f_console_verbosity_quiet;
+          main->error.verbosity = f_console_verbosity_quiet;
+          main->warning.verbosity = f_console_verbosity_quiet;
+        }
+        else if (choice == utf8_parameter_verbosity_normal) {
+          main->output.verbosity = f_console_verbosity_normal;
+          main->error.verbosity = f_console_verbosity_normal;
+          main->warning.verbosity = f_console_verbosity_normal;
+        }
+        else if (choice == utf8_parameter_verbosity_verbose) {
+          main->output.verbosity = f_console_verbosity_verbose;
+          main->error.verbosity = f_console_verbosity_verbose;
+          main->warning.verbosity = f_console_verbosity_verbose;
+        }
+        else if (choice == utf8_parameter_verbosity_debug) {
+          main->output.verbosity = f_console_verbosity_debug;
+          main->error.verbosity = f_console_verbosity_debug;
+          main->warning.verbosity = f_console_verbosity_debug;
+        }
+      }
+
+      // Identify and prioritize from mode parameters.
+      {
+        f_console_parameter_id_t ids[4] = { utf8_parameter_from_binary, utf8_parameter_from_codepoint };
+        f_console_parameter_id_t choice = 0;
+        const f_console_parameter_ids_t choices = macro_f_console_parameter_ids_t_initialize(ids, 2);
+
+        status = f_console_parameter_prioritize_right(parameters, choices, &choice);
+
+        if (F_status_is_error(status)) {
+          fll_error_print(main->error, F_status_set_fine(status), "f_console_parameter_prioritize_right", F_true);
+
+          utf8_main_delete(main);
+
+          return status;
+        }
+
+        if (choice == utf8_parameter_from_binary) {
+          if (main->mode & utf8_mode_from_codepoint_d) {
+            main->mode -= utf8_mode_from_codepoint_d;
+          }
+
+          main->mode |= utf8_mode_from_binary_d;
+        }
+        else if (choice == utf8_parameter_from_codepoint) {
+          if (main->mode & utf8_mode_from_binary_d) {
+            main->mode -= utf8_mode_from_binary_d;
+          }
+
+          main->mode |= utf8_mode_from_codepoint_d;
+        }
+      }
+
+      // Identify and prioritize to mode parameters.
+      {
+        f_console_parameter_id_t ids[4] = { utf8_parameter_to_binary, utf8_parameter_to_codepoint };
+        f_console_parameter_id_t choice = 0;
+        const f_console_parameter_ids_t choices = macro_f_console_parameter_ids_t_initialize(ids, 2);
+
+        status = f_console_parameter_prioritize_right(parameters, choices, &choice);
+
+        if (F_status_is_error(status)) {
+          fll_error_print(main->error, F_status_set_fine(status), "f_console_parameter_prioritize_right", F_true);
+
+          utf8_main_delete(main);
+
+          return status;
+        }
+
+        if (choice == utf8_parameter_to_binary) {
+          if (main->mode & utf8_mode_to_codepoint_d) {
+            main->mode -= utf8_mode_to_codepoint_d;
+          }
+
+          main->mode |= utf8_mode_to_binary_d;
+        }
+        else if (choice == utf8_parameter_to_codepoint) {
+          if (main->mode & utf8_mode_to_binary_d) {
+            main->mode -= utf8_mode_to_binary_d;
+          }
+
+          main->mode |= utf8_mode_to_codepoint_d;
+        }
+      }
+
+      status = F_none;
+    }
+
+    if (main->parameters[utf8_parameter_help].result == f_console_result_found) {
+      utf8_print_help(main->output.to, main->context);
+
+      utf8_main_delete(main);
+      return F_none;
+    }
+
+    if (main->parameters[utf8_parameter_version].result == f_console_result_found) {
+      fll_program_print_version(main->output.to, utf8_version_s);
+
+      utf8_main_delete(main);
+      return F_none;
+    }
+
+    if (main->parameters[utf8_parameter_from_binary].result == f_console_result_found) {
+      if (main->parameters[utf8_parameter_from_codepoint].result == f_console_result_found) {
+        utf8_print_error_parameter_conflict(main, utf8_long_from_binary_s, utf8_long_from_codepoint_s);
+
+        status = F_status_set_error(F_parameter);
+      }
+    }
+
+    if (F_status_is_error_not(status) && main->parameters[utf8_parameter_to_binary].result == f_console_result_found) {
+      if (main->parameters[utf8_parameter_to_codepoint].result == f_console_result_found) {
+        utf8_print_error_parameter_conflict(main, utf8_long_to_binary_s, utf8_long_to_codepoint_s);
+
+        status = F_status_set_error(F_parameter);
+      }
+    }
+
+    if (main->parameters[utf8_parameter_verify].result == f_console_result_found) {
+      if (main->parameters[utf8_parameter_strip_invalid].result == f_console_result_found) {
+        utf8_print_error_parameter_conflict(main, utf8_long_verify_s, utf8_long_strip_invalid_s);
+
+        status = F_status_set_error(F_parameter);
+      }
+    }
+
+    if (F_status_is_error_not(status)) {
+      if (main->parameters[utf8_parameter_from_file].result == f_console_result_additional) {
+        f_array_length_t i = 0;
+        f_array_length_t index = 0;
+
+        for (; i < main->parameters[utf8_parameter_from_file].values.used; ++i) {
+
+          index = main->parameters[utf8_parameter_from_file].values.array[i];
+
+          if (arguments->argv[index][0]) {
+            if (!f_file_exists(arguments->argv[index])) {
+              utf8_print_error_parameter_file_not_found(main, F_true, arguments->argv[index]);
+
+              if (F_status_is_error_not(status)) {
+                status = F_status_set_error(F_file_found_not);
+              }
+            }
+          }
+          else {
+            utf8_print_error_parameter_file_name_empty(main, index);
+
+            if (F_status_is_error_not(status)) {
+              status = F_status_set_error(F_parameter);
+            }
+          }
+        } // for
+      }
+      else if (main->parameters[utf8_parameter_from_file].result == f_console_result_found) {
+        utf8_print_error_no_value(main, utf8_long_from_file_s);
+
+        status = F_status_set_error(F_parameter);
+      }
+    }
+
+    bool valid = F_true;
+
+    if (F_status_is_error_not(status)) {
+      if (main->parameters[utf8_parameter_to_file].result == f_console_result_additional) {
+        if (main->parameters[utf8_parameter_to_file].values.used > 1) {
+          utf8_print_error_parameter_file_to_too_many(main);
+
+          status = F_status_set_error(F_parameter);
+        }
+        else {
+          const f_array_length_t index = main->parameters[utf8_parameter_to_file].values.array[0];
+
+          if (arguments->argv[index][0]) {
+            if (!f_file_exists(arguments->argv[index])) {
+              utf8_print_error_parameter_file_not_found(main, F_false, arguments->argv[index]);
+
+              status = F_status_set_error(F_file_found_not);
+            }
+          }
+          else {
+            utf8_print_error_parameter_file_name_empty(main, index);
+
+            status = F_status_set_error(F_parameter);
+          }
+        }
+      }
+      else if (main->parameters[utf8_parameter_to_file].result == f_console_result_found) {
+        utf8_print_error_no_value(main, utf8_long_to_file_s);
+
+        status = F_status_set_error(F_parameter);
+      }
+      else {
+        main->destination = main->output.to;
+      }
+    }
+
+    if (F_status_is_error_not(status)) {
+      if (main->parameters[utf8_parameter_from_file].result == f_console_result_none && !(main->process_pipe || main->remaining.used)) {
+        utf8_print_error_no_from(main);
+
+        status = F_status_set_error(F_parameter);
+      }
+    }
+
+    if (F_status_is_error_not(status)) {
+      status = F_none;
+
+      if (main->process_pipe) {
+        f_file_t file = f_file_t_initialize;
+
+        file.id = F_type_descriptor_input_d;
+        file.stream = F_type_input_d;
+
+        utf8_print_section_header_pipe(main);
+
+        if (main->mode & utf8_mode_from_binary_d) {
+          status = utf8_process_file_binary(main, file);
+        }
+        else {
+          status = utf8_process_file_codepoint(main, file);
+        }
+
+        if (F_status_is_error(status)) {
+          fll_error_file_print(main->error, F_status_set_fine(status), main->mode & utf8_mode_from_binary_d ? "utf8_process_file_binary" : "utf8_process_file_codepoint", F_true, 0, utf8_string_process_s, fll_error_file_type_pipe);
+        }
+      }
+
+      if (F_status_is_error_not(status) && status != F_signal && main->parameters[utf8_parameter_from_file].result == f_console_result_additional) {
+        f_array_length_t i = 0;
+        f_array_length_t index = 0;
+
+        f_file_t file = f_file_t_initialize;
+        file.size_read = 32768;
+
+        for (; i < main->parameters[utf8_parameter_from_file].values.used && status != F_signal; ++i) {
+
+          if (utf8_signal_received(main)) {
+            status = F_status_set_error(F_signal);
+            break;
+          }
+
+          index = main->parameters[utf8_parameter_from_file].values.array[i];
+
+          utf8_print_section_header_file(main, arguments->argv[index]);
+
+          status = f_file_stream_open(arguments->argv[index], 0, &file);
+
+          if (F_status_is_error(status)) {
+            fll_error_file_print(main->error, F_status_set_fine(status), "f_file_stream_open", F_true, arguments->argv[index], utf8_string_open_s, fll_error_file_type_file);
+
+            break;
+          }
+
+          if (main->mode & utf8_mode_from_binary_d) {
+            status = utf8_process_file_binary(main, file);
+          }
+          else {
+            status = utf8_process_file_codepoint(main, file);
+          }
+
+          f_file_stream_close(F_true, &file);
+
+          if (main->parameters[utf8_parameter_verify].result == f_console_result_found) {
+            if (status == F_false) {
+              valid = F_false;
+            }
+          }
+
+          if (F_status_is_error(status)) {
+            fll_error_file_print(main->error, F_status_set_fine(status), main->mode & utf8_mode_from_binary_d ? "utf8_process_file_binary" : "utf8_process_file_codepoint", F_true, arguments->argv[index], utf8_string_process_s, fll_error_file_type_file);
+
+            break;
+          }
+        } // for
+      }
+
+      if (F_status_is_error_not(status) && status != F_signal && main->remaining.used) {
+        f_array_length_t i = 0;
+        f_array_length_t index = 0;
+
+        for (; F_status_is_error_not(status) && i < main->remaining.used; ++i) {
+
+          if (utf8_signal_received(main)) {
+            status = F_status_set_error(F_signal);
+            break;
+          }
+
+          index = main->remaining.array[i];
+
+          utf8_print_section_header_parameter(main, index);
+
+          status = utf8_process_text(main, arguments->argv[index]);
+
+          if (main->parameters[utf8_parameter_verify].result == f_console_result_found) {
+            if (status == F_false) {
+              valid = F_false;
+            }
+          }
+        } // for
+      }
+    }
+
+    if (main->output.verbosity != f_console_verbosity_quiet) {
+      if (F_status_set_fine(status) == F_interrupt) {
+        fflush(main->output.to.stream);
+      }
+
+      fll_print_terminated(f_string_eol_s, main->output.to.stream);
+    }
+
+    utf8_main_delete(main);
+
+    if (F_status_is_error(status)) {
+      return status;
+    }
+
+    return valid;
+  }
+#endif // _di_utf8_main_
+
+#ifndef _di_utf8_main_delete_
+  f_status_t utf8_main_delete(utf8_main_t *main) {
+
+    for (f_array_length_t i = 0; i < utf8_total_parameters_d; ++i) {
+
+      macro_f_array_lengths_t_delete_simple(main->parameters[i].locations);
+      macro_f_array_lengths_t_delete_simple(main->parameters[i].locations_sub);
+      macro_f_array_lengths_t_delete_simple(main->parameters[i].values);
+    } // for
+
+    macro_f_string_dynamic_t_delete_simple(main->buffer);
+    macro_f_string_dynamic_t_delete_simple(main->file_input);
+    macro_f_string_dynamic_t_delete_simple(main->file_output);
+    macro_f_string_dynamic_t_delete_simple(main->text);
+
+    macro_f_string_dynamic_t_delete_simple(main->separate_character);
+    macro_f_string_dynamic_t_delete_simple(main->separate_source);
+
+    macro_f_array_lengths_t_delete_simple(main->remaining);
+
+    macro_f_color_context_t_delete_simple(main->context);
+
+    return F_none;
+  }
+#endif // _di_utf8_main_delete_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_3/utf8/c/utf8.h b/level_3/utf8/c/utf8.h
new file mode 100644 (file)
index 0000000..585d05e
--- /dev/null
@@ -0,0 +1,311 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: UTF-8
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ *
+ * This is intendend to support Unicode 14.0.
+ *
+ * This is a program for handling basic UTF-8 related conversions.
+ * - Convert from UTF-8 character to binary.
+ * - Convert from Unicode Codepoint (such as U+0000) to binary.
+ * - Convert from UTF-8 binary to character.
+ * - Convert from UTF-8 binary to Unicode Codepoint (such as U+0000).
+ */
+#ifndef _utf8_h
+
+// libc includes
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+// fll-0 includes
+#include <fll/level_0/type.h>
+#include <fll/level_0/status.h>
+#include <fll/level_0/memory.h>
+#include <fll/level_0/string.h>
+#include <fll/level_0/utf.h>
+#include <fll/level_0/color.h>
+#include <fll/level_0/console.h>
+#include <fll/level_0/conversion.h>
+#include <fll/level_0/file.h>
+#include <fll/level_0/pipe.h>
+#include <fll/level_0/print.h>
+#include <fll/level_0/signal.h>
+
+// fll-1 includes
+#include <fll/level_1/console.h>
+#include <fll/level_1/conversion.h>
+#include <fll/level_1/print.h>
+#include <fll/level_1/string.h>
+#include <fll/level_1/utf.h>
+
+// fll-2 includes
+#include <fll/level_2/error.h>
+#include <fll/level_2/print.h>
+#include <fll/level_2/program.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_utf8_program_version_
+  #define utf8_program_version_major_s F_string_ascii_0_s
+  #define utf8_program_version_minor_s F_string_ascii_5_s
+  #define utf8_program_version_micro_s F_string_ascii_7_s
+
+  #ifndef utf8_program_version_nano_prefix_s
+    #define utf8_program_version_nano_prefix_s
+  #endif
+
+  #ifndef utf8_program_version_nano_s
+    #define utf8_program_version_nano_s
+  #endif
+
+  #define utf8_version_s utf8_program_version_major_s F_string_ascii_period_s utf8_program_version_minor_s F_string_ascii_period_s utf8_program_version_micro_s utf8_program_version_nano_prefix_s utf8_program_version_nano_s
+#endif // _di_utf8_program_version_
+
+#ifndef _di_utf8_program_name_
+  #define utf8_program_name_s      "utf8"
+  #define utf8_program_name_long_s "UTF-8"
+#endif // _di_utf8_program_name_
+
+/**
+ * Set to at least 4 to provide a UTF-8 friendly allocation step.
+ */
+#ifndef _di_utf8_default_allocation_step_
+  #define utf8_default_allocation_step_d 4
+#endif // _di_utf8_default_allocation_step_
+
+#ifndef _di_utf8_defines_
+  #define utf8_string_from_s "from"
+  #define utf8_string_to_s   "to"
+
+  #define utf8_string_open_s    "open"
+  #define utf8_string_process_s "process"
+
+  #define utf8_string_verified_valid_s     "Verified Valid"
+  #define utf8_string_verified_valid_not_s "Verified Invalid"
+
+  #define utf8_string_from_s_length 4
+  #define utf8_string_to_s_length   2
+
+  #define utf8_string_open_s_length    4
+  #define utf8_string_process_s_length 7
+
+  #define utf8_string_verified_valid_s_length     14
+  #define utf8_string_verified_valid_not_s_length 16
+
+  #define utf8_character_valid_not_s "�"
+
+  #define utf8_short_from_binary_s    "b"
+  #define utf8_short_from_codepoint_s "c"
+  #define utf8_short_from_file_s      "f"
+
+  #define utf8_short_headers_s       "H"
+  #define utf8_short_strip_invalid_s "s"
+  #define utf8_short_verify_s        "v"
+
+  #define utf8_short_to_binary_s    "B"
+  #define utf8_short_to_codepoint_s "C"
+  #define utf8_short_to_file_s      "F"
+
+  #define utf8_long_from_binary_s    "from_binary"
+  #define utf8_long_from_codepoint_s "from_codepoint"
+  #define utf8_long_from_file_s      "from_file"
+
+  #define utf8_long_headers_s       "headers"
+  #define utf8_long_strip_invalid_s "strip_invalid"
+  #define utf8_long_verify_s        "verify"
+
+  #define utf8_long_to_binary_s    "to_binary"
+  #define utf8_long_to_codepoint_s "to_codepoint"
+  #define utf8_long_to_file_s      "to_file"
+
+  enum {
+    utf8_parameter_help,
+    utf8_parameter_light,
+    utf8_parameter_dark,
+    utf8_parameter_no_color,
+    utf8_parameter_verbosity_quiet,
+    utf8_parameter_verbosity_normal,
+    utf8_parameter_verbosity_verbose,
+    utf8_parameter_verbosity_debug,
+    utf8_parameter_version,
+
+    utf8_parameter_from_binary,
+    utf8_parameter_from_codepoint,
+    utf8_parameter_from_file,
+
+    utf8_parameter_headers,
+    utf8_parameter_strip_invalid,
+
+    utf8_parameter_to_binary,
+    utf8_parameter_to_codepoint,
+    utf8_parameter_to_file,
+
+    utf8_parameter_verify,
+  };
+
+  #define utf8_console_parameter_t_initialize \
+    { \
+      f_console_parameter_t_initialize(f_console_standard_short_help_s, f_console_standard_long_help_s, 0, 0, f_console_type_normal), \
+      f_console_parameter_t_initialize(f_console_standard_short_light_s, f_console_standard_long_light_s, 0, 0, f_console_type_inverse), \
+      f_console_parameter_t_initialize(f_console_standard_short_dark_s, f_console_standard_long_dark_s, 0, 0, f_console_type_inverse), \
+      f_console_parameter_t_initialize(f_console_standard_short_no_color_s, f_console_standard_long_no_color_s, 0, 0, f_console_type_inverse), \
+      f_console_parameter_t_initialize(f_console_standard_short_quiet_s, f_console_standard_long_quiet_s, 0, 0, f_console_type_inverse), \
+      f_console_parameter_t_initialize(f_console_standard_short_normal_s, f_console_standard_long_normal_s, 0, 0, f_console_type_inverse), \
+      f_console_parameter_t_initialize(f_console_standard_short_verbose_s, f_console_standard_long_verbose_s, 0, 0, f_console_type_inverse), \
+      f_console_parameter_t_initialize(f_console_standard_short_debug_s, f_console_standard_long_debug_s, 0, 0, f_console_type_inverse), \
+      f_console_parameter_t_initialize(f_console_standard_short_version_s, f_console_standard_long_version_s, 0, 0, f_console_type_inverse), \
+      f_console_parameter_t_initialize(utf8_short_from_binary_s, utf8_long_from_binary_s, 0, 0, f_console_type_normal), \
+      f_console_parameter_t_initialize(utf8_short_from_codepoint_s, utf8_long_from_codepoint_s, 0, 0, f_console_type_normal), \
+      f_console_parameter_t_initialize(utf8_short_from_file_s, utf8_long_from_file_s, 0, 1, f_console_type_normal), \
+      f_console_parameter_t_initialize(utf8_short_headers_s, utf8_long_headers_s, 0, 0, f_console_type_normal), \
+      f_console_parameter_t_initialize(utf8_short_strip_invalid_s, utf8_long_strip_invalid_s, 0, 0, f_console_type_normal), \
+      f_console_parameter_t_initialize(utf8_short_to_binary_s, utf8_long_to_binary_s, 0, 0, f_console_type_normal), \
+      f_console_parameter_t_initialize(utf8_short_to_codepoint_s, utf8_long_to_codepoint_s, 0, 0, f_console_type_normal), \
+      f_console_parameter_t_initialize(utf8_short_to_file_s, utf8_long_to_file_s, 0, 1, f_console_type_normal), \
+      f_console_parameter_t_initialize(utf8_short_verify_s, utf8_long_verify_s, 0, 0, f_console_type_normal), \
+    }
+
+  #define utf8_total_parameters_d 18
+#endif // _di_utf8_defines_
+
+/**
+ * utf8_mode_from_*:
+ *   - binary:    The input source is binary.
+ *   - codepoint: The input source is codepoint (U+XXXX or U+XXXXXX).
+ *
+ * utf8_mode_to_*:
+ *   - binary:    The outout destination is binary.
+ *   - codepoint: The outout destination is codepoint (U+XXXX or U+XXXXXX).
+ */
+#ifndef _di_utf8_modes_
+  #define utf8_mode_from_binary_d    0x1
+  #define utf8_mode_from_codepoint_d 0x2
+  #define utf8_mode_to_binary_d      0x4
+  #define utf8_mode_to_codepoint_d   0x8
+#endif // _di_utf8_modes_
+
+#ifndef _di_utf8_main_t_
+  typedef struct {
+    f_console_parameter_t parameters[utf8_total_parameters_d];
+
+    f_array_lengths_t remaining;
+    bool process_pipe;
+
+    fl_print_t output;
+    fl_print_t error;
+    fl_print_t warning;
+
+    f_signal_t signal;
+
+    f_file_t destination;
+    uint8_t mode;
+
+    f_string_dynamic_t buffer;
+    f_string_dynamic_t file_input;
+    f_string_dynamic_t file_output;
+    f_string_dynamic_t text;
+
+    f_string_dynamic_t separate_character;
+    f_string_dynamic_t separate_source;
+
+    f_color_context_t context;
+  } utf8_main_t;
+
+  #define utf8_main_t_initialize \
+    { \
+      utf8_console_parameter_t_initialize, \
+      f_array_lengths_t_initialize, \
+      F_false, \
+      fl_print_t_initialize, \
+      macro_fl_print_t_initialize_error(), \
+      macro_fl_print_t_initialize_warning(), \
+      f_signal_t_initialize, \
+      f_file_t_initialize, \
+      utf8_mode_from_binary_d | utf8_mode_to_codepoint_d, \
+      f_string_dynamic_t_initialize, \
+      f_string_dynamic_t_initialize, \
+      f_string_dynamic_t_initialize, \
+      f_string_dynamic_t_initialize, \
+      f_string_dynamic_t_initialize, \
+      f_string_dynamic_t_initialize, \
+      f_color_context_t_initialize, \
+    }
+#endif // _di_utf8_main_t_
+
+/**
+ * Print help.
+ *
+ * @param file
+ *   The file to print to.
+ * @param context
+ *   The color context settings.
+ *
+ * @return
+ *   F_none on success.
+ */
+#ifndef _di_utf8_print_help_
+  extern f_status_t utf8_print_help(const f_file_t file, const f_color_context_t context);
+#endif // _di_utf8_print_help_
+
+/**
+ * Execute main program.
+ *
+ * Be sure to call utf8_main_delete() after executing this.
+ *
+ * If main.signal is non-zero, then this blocks and handles the following signals:
+ * - F_signal_abort
+ * - F_signal_broken_pipe
+ * - F_signal_hangup
+ * - F_signal_interrupt
+ * - F_signal_quit
+ * - F_signal_termination
+ *
+ * @param main
+ *   The main program data.
+ * @param arguments
+ *   The parameters passed to the process.
+ *
+ * @return
+ *   F_none on success.
+ *   F_true on success when performing verification and verify passed.
+ *   F_false on success when performing verification and verify failed.
+ *   F_signal on (exit) signal received.
+ *
+ *   Status codes (with error bit) are returned on any problem.
+ *
+ * @see utf8_main_delete()
+ */
+#ifndef _di_utf8_main_
+  extern f_status_t utf8_main(utf8_main_t * const main, const f_console_arguments_t *arguments);
+#endif // _di_utf8_main_
+
+/**
+ * Deallocate main.
+ *
+ * Be sure to call this after executing utf8_main().
+ *
+ * @param main
+ *   The main program data.
+ *
+ * @return
+ *   F_none on success.
+ *
+ *   Status codes (with error bit) are returned on any problem.
+ *
+ * @see utf8_main()
+ */
+#ifndef _di_utf8_main_delete_
+  extern f_status_t utf8_main_delete(utf8_main_t *main);
+#endif // _di_utf8_main_delete_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _utf8_h
diff --git a/level_3/utf8/data/build/defines b/level_3/utf8/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_3/utf8/data/build/dependencies b/level_3/utf8/data/build/dependencies
new file mode 100644 (file)
index 0000000..fa07553
--- /dev/null
@@ -0,0 +1,21 @@
+# fss-0000
+
+f_type
+f_status
+f_memory
+f_string
+f_utf
+f_color
+f_console
+f_conversion
+f_file
+f_pipe
+f_print
+f_signal
+fl_console
+fl_conversion
+fl_print
+fl_string
+fll_error
+fll_print
+fll_program
diff --git a/level_3/utf8/data/build/settings b/level_3/utf8/data/build/settings
new file mode 100644 (file)
index 0000000..2de6a54
--- /dev/null
@@ -0,0 +1,78 @@
+# fss-0001
+
+project_name utf8
+
+version_major 0
+version_minor 5
+version_micro 7
+version_file micro
+version_target minor
+
+environment
+
+process_pre
+process_post
+
+modes individual level monolithic
+modes_default monolithic
+
+build_compiler gcc
+build_indexer ar
+build_indexer_arguments rcs
+build_language c
+build_libraries -lc
+build_libraries-individual -lfll_error -lfll_print -lfll_program -lfl_console -lfl_conversion -lfl_print -lfl_string -lf_color -lf_console -lf_conversion -lf_file -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_string -lf_type_array -lf_utf
+build_libraries-level -lfll_2 -lfll_1 -lfll_0
+build_libraries-monolithic -lfll
+build_libraries_shared
+build_libraries_static
+build_sources_library utf8.c private-common.c private-utf8.c
+build_sources_library_shared
+build_sources_library_static
+build_sources_program main.c
+build_sources_program_shared
+build_sources_program_static
+build_sources_headers utf8.h
+build_sources_headers_shared
+build_sources_headers_static
+build_sources_script
+build_sources_setting
+build_script yes
+build_shared yes
+build_static no
+
+path_headers program/utf8
+path_headers_preserve no
+path_library_script script
+path_library_shared shared
+path_library_static static
+path_program_script script
+path_program_shared shared
+path_program_static static
+path_sources
+path_standard yes
+
+search_exclusive yes
+search_shared yes
+search_static yes
+
+#defines -D_di_libcap_ -D_di_thread_support_
+defines -D_libcap_legacy_only_ -D_pthread_attr_unsupported_ -D_pthread_sigqueue_unsupported_
+defines_library
+defines_library_shared
+defines_library_static
+defines_program
+defines_program_shared
+defines_program_static
+defines_static
+defines_shared
+
+flags -O2 -z now -g -fdiagnostics-color=always -Wno-logical-not-parentheses -Wno-logical-op-parentheses -Wno-parentheses
+flags_library -fPIC
+flags_library_shared
+flags_library_static
+flags_program -fPIE
+flags_program_shared
+flags_program_static
+flags_shared
+flags_static