]> Kevux Git Server - fll/commitdiff
Feature: add iki_write and all related dependencies.
authorKevin Day <thekevinday@gmail.com>
Sat, 19 Sep 2020 00:39:05 +0000 (19:39 -0500)
committerKevin Day <thekevinday@gmail.com>
Sat, 19 Sep 2020 02:07:30 +0000 (21:07 -0500)
24 files changed:
build/level_0/settings
build/level_2/settings
build/monolithic/settings
build/scripts/bootstrap-example.sh
level_0/f_iki/c/iki.c
level_0/f_iki/c/iki.h
level_0/f_iki/c/private-iki.c [new file with mode: 0644]
level_0/f_iki/c/private-iki.h [new file with mode: 0644]
level_0/f_iki/data/build/settings
level_2/fll_iki/c/iki.c [new file with mode: 0644]
level_2/fll_iki/c/iki.h [new file with mode: 0644]
level_2/fll_iki/c/private-iki.c [new file with mode: 0644]
level_2/fll_iki/c/private-iki.h [new file with mode: 0644]
level_2/fll_iki/data/build/defines [new file with mode: 0644]
level_2/fll_iki/data/build/dependencies [new file with mode: 0644]
level_2/fll_iki/data/build/settings [new file with mode: 0644]
level_3/iki_write/c/iki_write.c [new file with mode: 0644]
level_3/iki_write/c/iki_write.h [new file with mode: 0644]
level_3/iki_write/c/main.c [new file with mode: 0644]
level_3/iki_write/c/private-iki_write.c [new file with mode: 0644]
level_3/iki_write/c/private-iki_write.h [new file with mode: 0644]
level_3/iki_write/data/build/defines [new file with mode: 0644]
level_3/iki_write/data/build/dependencies [new file with mode: 0644]
level_3/iki_write/data/build/settings [new file with mode: 0644]

index 565a1ac19191a7733b9d01df991e192068682b53..fc78356b9ea185ee429e4c1aaaaaae92ac1980ee 100644 (file)
@@ -20,7 +20,7 @@ build_indexer ar
 build_language c
 build_libraries -lc
 build_libraries-level
-build_sources_library account.c console.c conversion.c directory.c private-directory.c environment.c private-environment.c file.c private-file.c fss.c iki.c memory.c path.c private-path.c pipe.c print.c serialize.c private-serialize.c signal.c socket.c utf.c private-utf.c
+build_sources_library account.c console.c conversion.c directory.c private-directory.c environment.c private-environment.c file.c private-file.c fss.c iki.c private-iki.c memory.c path.c private-path.c pipe.c print.c serialize.c private-serialize.c signal.c socket.c utf.c private-utf.c
 build_sources_program
 build_sources_headers account.h color.h console.h conversion.h directory.h directory_type.h environment.h file.h fss.h fss-common.h fss-named.h fss-nest.h fss-quoted.h fss-set.h iki.h iki-common.h memory.h memory-structure.h path.h pipe.h print.h serialize.h signal.h socket.h status.h status_array.h string.h string_common.h string_dynamic.h string_map.h string_quantity.h string_range.h type.h type_array.h utf.h utf-common.h
 build_sources_script
index 6055baa218118a837478c514860d3bf1971865f0..1c5ce910b0ae66b874c8caf3d7bf773695292bf5 100644 (file)
@@ -20,9 +20,9 @@ build_indexer ar
 build_language c
 build_libraries -lc
 build_libraries-level -lfll_1 -lfll_0
-build_sources_library execute.c private-execute.c file.c private-file.c fss.c private-fss.c fss_basic.c fss_basic_list.c fss_extended.c fss_extended_list.c fss_status.c path.c program.c status.c
+build_sources_library execute.c private-execute.c file.c private-file.c fss.c private-fss.c fss_basic.c fss_basic_list.c fss_extended.c fss_extended_list.c fss_status.c iki.c private-iki.c path.c program.c status.c
 build_sources_program
-build_sources_headers execute.h file.h fss.h fss_basic.h fss_basic_list.h fss_extended.h fss_extended_list.h fss_status.h path.h program.h status.h
+build_sources_headers execute.h file.h fss.h fss_basic.h fss_basic_list.h fss_extended.h fss_extended_list.h fss_status.h iki.h path.h program.h status.h
 build_sources_script
 build_sources_setting
 build_script yes
index 99a6d86fe32a4db16960554c2064eb83795b9064..ffb50c00a483280773279103cb237ea260b697c8 100644 (file)
@@ -20,9 +20,9 @@ build_indexer ar
 build_language c
 build_libraries -lc
 build_libraries-monolithic
-build_sources_library level_0/account.c level_0/console.c level_0/conversion.c level_0/directory.c level_0/private-directory.c level_0/environment.c level_0/private-environment.c level_0/file.c level_0/private-file.c level_0/fss.c level_0/iki.c level_0/memory.c level_0/path.c level_0/private-path.c level_0/pipe.c level_0/print.c level_0/serialize.c level_0/private-serialize.c level_0/signal.c level_0/socket.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/conversion.c level_1/directory.c level_1/private-directory.c level_1/environment.c level_1/private-fss.c level_1/fss_basic.c level_1/fss_basic_list.c level_1/fss_extended.c level_1/fss_extended_list.c level_1/iki.c level_1/print.c level_1/status.c level_1/string.c level_1/private-string.c level_1/utf.c level_1/private-utf.c level_1/utf_file.c level_1/private-utf_file.c level_2/execute.c level_2/private-execute.c level_2/file.c level_2/private-file.c level_2/fss.c level_2/private-fss.c level_2/fss_basic.c level_2/fss_basic_list.c level_2/fss_extended.c level_2/fss_extended_list.c level_2/fss_status.c level_2/path.c level_2/program.c level_2/status.c
+build_sources_library level_0/account.c level_0/console.c level_0/conversion.c level_0/directory.c level_0/private-directory.c level_0/environment.c level_0/private-environment.c level_0/file.c level_0/private-file.c level_0/fss.c level_0/iki.c level_0/private-iki.c level_0/memory.c level_0/path.c level_0/private-path.c level_0/pipe.c level_0/print.c level_0/serialize.c level_0/private-serialize.c level_0/signal.c level_0/socket.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/conversion.c level_1/directory.c level_1/private-directory.c level_1/environment.c level_1/private-fss.c level_1/fss_basic.c level_1/fss_basic_list.c level_1/fss_extended.c level_1/fss_extended_list.c level_1/iki.c level_1/print.c level_1/status.c level_1/string.c level_1/private-string.c level_1/utf.c level_1/private-utf.c level_1/utf_file.c level_1/private-utf_file.c level_2/execute.c level_2/private-execute.c level_2/file.c level_2/private-file.c level_2/fss.c level_2/private-fss.c level_2/fss_basic.c level_2/fss_basic_list.c level_2/fss_extended.c level_2/fss_extended_list.c level_2/fss_status.c level_2/iki.c level_2/private-iki.c level_2/path.c level_2/program.c level_2/status.c
 build_sources_program
-build_sources_headers level_0/account.h level_0/color.h level_0/console.h level_0/conversion.h level_0/directory.h level_0/directory_type.h level_0/environment.h level_0/file.h level_0/fss.h level_0/fss-common.h level_0/fss-named.h level_0/fss-nest.h level_0/fss-quoted.h level_0/fss-set.h level_0/iki.h level_0/iki-common.h level_0/memory.h level_0/memory-structure.h level_0/path.h level_0/pipe.h level_0/print.h level_0/serialize.h level_0/signal.h level_0/socket.h level_0/status.h level_0/status_array.h level_0/string.h level_0/string_common.h level_0/string_dynamic.h level_0/string_map.h level_0/string_quantity.h level_0/string_range.h level_0/type.h level_0/type_array.h level_0/utf.h level_0/utf-common.h level_1/color.h level_1/console.h level_1/conversion.h level_1/directory.h level_1/environment.h level_1/fss.h level_1/fss_basic.h level_1/fss_basic_list.h level_1/fss_extended.h level_1/fss_extended_list.h level_1/fss_macro.h level_1/fss_status.h level_1/iki.h level_1/print.h level_1/status.h level_1/string.h level_1/utf.h level_1/utf_file.h level_2/execute.h level_2/file.h level_2/fss.h level_2/fss_basic.h level_2/fss_basic_list.h level_2/fss_extended.h level_2/fss_extended_list.h level_2/fss_status.h level_2/path.h level_2/program.h level_2/status.h
+build_sources_headers level_0/account.h level_0/color.h level_0/console.h level_0/conversion.h level_0/directory.h level_0/directory_type.h level_0/environment.h level_0/file.h level_0/fss.h level_0/fss-common.h level_0/fss-named.h level_0/fss-nest.h level_0/fss-quoted.h level_0/fss-set.h level_0/iki.h level_0/iki-common.h level_0/memory.h level_0/memory-structure.h level_0/path.h level_0/pipe.h level_0/print.h level_0/serialize.h level_0/signal.h level_0/socket.h level_0/status.h level_0/status_array.h level_0/string.h level_0/string_common.h level_0/string_dynamic.h level_0/string_map.h level_0/string_quantity.h level_0/string_range.h level_0/type.h level_0/type_array.h level_0/utf.h level_0/utf-common.h level_1/color.h level_1/console.h level_1/conversion.h level_1/directory.h level_1/environment.h level_1/fss.h level_1/fss_basic.h level_1/fss_basic_list.h level_1/fss_extended.h level_1/fss_extended_list.h level_1/fss_macro.h level_1/fss_status.h level_1/iki.h level_1/print.h level_1/status.h level_1/string.h level_1/utf.h level_1/utf_file.h level_2/execute.h level_2/file.h level_2/fss.h level_2/fss_basic.h level_2/fss_basic_list.h level_2/fss_extended.h level_2/fss_extended_list.h level_2/fss_status.h level_2/iki.h level_2/path.h level_2/program.h level_2/status.h
 build_sources_script
 build_sources_setting
 build_script yes
index cf48c8b3d3e3acb3bb7d9f20e2119767997423ee..e70a18cc235efc79f7bd31837801ae116afc9c25 100644 (file)
@@ -23,7 +23,7 @@ if [[ $1 == "individual" ]] ; then
   bash build/scripts/package.sh build -i
 
   if [[ $? -eq 0 ]] ; then
-    for i in f_type f_status f_memory f_string f_utf f_account f_color f_console f_conversion f_directory f_environment f_file f_fss f_iki f_path f_pipe f_print f_serialize f_signal f_socket fl_color fl_console fl_conversion fl_directory fl_environment fl_fss fl_iki fl_print fl_status fl_string fl_utf fl_utf_file fll_execute fll_file fll_fss fll_path fll_program fll_status ; do
+    for i in f_type f_status f_memory f_string f_utf f_account f_color f_console f_conversion f_directory f_environment f_file f_fss f_iki f_path f_pipe f_print f_serialize f_signal f_socket fl_color fl_console fl_conversion fl_directory fl_environment fl_fss fl_iki fl_print fl_status fl_string fl_utf fl_utf_file fll_execute fll_file fll_fss fll_iki fll_path fll_program fll_status ; do
       echo && echo "Processing $i." &&
 
       cd package/individual/$i-$2/ &&
index 40911f04c7b23c00a718eaa30a2c028bc0e25d2d..e227a180b07dddddd79abc4d9b1abb8f375e67ee 100644 (file)
@@ -1,9 +1,60 @@
 #include "iki.h"
+#include "private-iki.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+#ifndef _di_f_iki_content_is_
+  f_return_status f_iki_content_is(const f_string_static_t content, const uint8_t quote) {
+    #ifndef _di_level_0_parameter_checking_
+      if (content.used > content.size) return F_status_set_error(F_parameter);
+      if (quote != f_iki_syntax_quote_single && quote != f_iki_syntax_quote_double) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    const f_string_range_t range = f_macro_string_range_t_initialize(content.used);
+
+    return private_f_iki_content_partial_is(content, range, quote);
+  }
+#endif // _di_f_iki_content_is_
+
+#ifndef _di_f_iki_content_partial_is_
+  f_return_status f_iki_content_partial_is(const f_string_static_t content, const f_string_range_t range, const uint8_t quote) {
+    #ifndef _di_level_0_parameter_checking_
+      if (content.used > content.size) return F_status_set_error(F_parameter);
+      if (range.start > range.stop) return F_status_set_error(F_parameter);
+      if (range.start >= content.used) return F_status_set_error(F_parameter);
+      if (quote != f_iki_syntax_quote_single && quote != f_iki_syntax_quote_double) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    return private_f_iki_content_partial_is(content, range, quote);
+  }
+#endif // _di_f_iki_content_partial_is_
+
+#ifndef _di_f_iki_object_is_
+  f_return_status f_iki_object_is(const f_string_static_t object) {
+    #ifndef _di_level_0_parameter_checking_
+      if (object.used > object.size) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    const f_string_range_t range = f_macro_string_range_t_initialize(object.used);
+
+    return private_f_iki_object_partial_is(object, range);
+  }
+#endif // _di_f_iki_object_is_
+
+#ifndef _di_f_iki_object_partial_is_
+  f_return_status f_iki_object_partial_is(const f_string_static_t object, const f_string_range_t range) {
+    #ifndef _di_level_0_parameter_checking_
+      if (object.used > object.size) return F_status_set_error(F_parameter);
+      if (range.start > range.stop) return F_status_set_error(F_parameter);
+      if (range.start >= object.used) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    return private_f_iki_object_partial_is(object, range);
+  }
+#endif // _di_f_iki_object_partial_is_
+
 #ifndef _di_f_iki_read_
   f_return_status f_iki_read(f_string_static_t *buffer, f_string_range_t *range, f_iki_variable_t *variable, f_iki_vocabulary_t *vocabulary, f_iki_content_t *content) {
     #ifndef _di_level_0_parameter_checking_
@@ -38,7 +89,7 @@ extern "C" {
       return F_data_not_eos;
     }
 
-    f_string_range_t found_vocabulary = f_string_range_initialize;
+    f_string_range_t found_vocabulary = f_string_range_t_initialize;
     f_string_length_t found_content = 0;
 
     found_vocabulary.start = range->start;
@@ -270,7 +321,7 @@ extern "C" {
 
               if (buffer->string[range->start] == quote) {
                 f_array_length_t content_slash_delimits = content_slash_total / 2;
-                f_string_range_t content_range = f_string_range_initialize;
+                f_string_range_t content_range = f_string_range_t_initialize;
                 f_array_length_t i = 0;
 
                 if (content_slash_total % 2) {
index 503277c73e27bc2c01f4a613d8d4102583b5424c..807aacb2865bc638f6a5da90611ad7145b9d7c07 100644 (file)
@@ -32,6 +32,80 @@ extern "C" {
 #endif
 
 /**
+ * Determine if an content is a valid IKI content name.
+ *
+ * @param content
+ *   The string to validate as an content name.
+ * @param quote
+ *   The quote character in use.
+ *   This must be either a single (') or double (") quote.
+ *
+ * @return
+ *   F_true on success and string is a valid content name.
+ *   F_false on success and string is not a valid content name.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ */
+#ifndef _di_f_iki_content_is_
+  extern f_return_status f_iki_content_is(const f_string_static_t content, const uint8_t quote);
+#endif // _di_f_iki_content_is_
+
+/**
+ * Determine if an content, found within the given range, is a valid IKI content name.
+ *
+ * @param content
+ *   The string to validate as an content name.
+ * @param range
+ *   The range within the buffer that represents the content name.
+ * @param quote
+ *   The quote character in use.
+ *   This must be either a single (') or double (") quote.
+ *
+ * @return
+ *   F_true on success and string is a valid content name.
+ *   F_false on success and string is not a valid content name.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ */
+#ifndef _di_f_iki_content_partial_is_
+  extern f_return_status f_iki_content_partial_is(const f_string_static_t content, const f_string_range_t range, const uint8_t quote);
+#endif // _di_f_iki_content_partial_is_
+
+/**
+ * Determine if an object is a valid IKI object name.
+ *
+ * @param object
+ *   The string to validate as an object name.
+ *
+ * @return
+ *   F_true on success and string is a valid object name.
+ *   F_false on success and string is not a valid object name.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ *   Errors from (with error bit): f_utf_is_word().
+ */
+#ifndef _di_f_iki_object_is_
+  extern f_return_status f_iki_object_is(const f_string_static_t object);
+#endif // _di_f_iki_object_is_
+
+/**
+ * Determine if an object, found within the buffer, is a valid IKI object name.
+ *
+ * @param object
+ *   The string to validate as an object name.
+ * @param range
+ *   The range within the buffer that represents the object name.
+ *
+ * @return
+ *   F_true on success and string is a valid object name.
+ *   F_false on success and string is not a valid object name.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ *   Errors from (with error bit): f_utf_is_word().
+ */
+#ifndef _di_f_iki_object_partial_is_
+  extern f_return_status f_iki_object_partial_is(const f_string_static_t object, const f_string_range_t range);
+#endif // _di_f_iki_object_partial_is_
+
+/**
  * Read a single iki Vocabulary and Content.
  *
  * This does not verify if the vocabulary name is known.
diff --git a/level_0/f_iki/c/private-iki.c b/level_0/f_iki/c/private-iki.c
new file mode 100644 (file)
index 0000000..d45ea1d
--- /dev/null
@@ -0,0 +1,52 @@
+#include "iki.h"
+#include "private-iki.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(_di_f_iki_content_is_) || !defined(_di_f_iki_content_partial_is_)
+  f_return_status private_f_iki_content_partial_is(const f_string_static_t buffer, const f_string_range_t range, const uint8_t quote) {
+    f_string_length_t delimits = 0;
+
+    for (f_string_length_t i = 0; i < buffer.used; i++) {
+
+      if (buffer.string[i] == quote) {
+        if (delimits && delimits % 2) {
+          delimits = 0;
+          continue;
+        }
+
+        return F_false;
+      }
+      else if (buffer.string[i] == f_iki_syntax_slash) {
+        delimits++;
+      }
+      else {
+        delimits = 0;
+      }
+    } // for
+
+    return F_true;
+  }
+#endif // !defined(_di_f_iki_content_is_) || !defined(_di_f_iki_content_partial_is_)
+
+#if !defined(_di_f_iki_object_is_) || !defined(_di_f_iki_object_partial_is_)
+  f_return_status private_f_iki_object_partial_is(const f_string_static_t buffer, const f_string_range_t range) {
+    f_status_t status = F_none;
+
+    for (f_string_length_t i = 0; i < buffer.used; i++) {
+
+      status = f_utf_is_word(buffer.string + i, buffer.used - i, F_false);
+      if (F_status_is_error(status)) return status;
+
+      if (status == F_false) return F_false;
+    } // for
+
+    return F_true;
+  }
+#endif // !defined(_di_f_iki_object_is_) || !defined(_di_f_iki_object_partial_is_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_iki/c/private-iki.h b/level_0/f_iki/c/private-iki.h
new file mode 100644 (file)
index 0000000..bba6738
--- /dev/null
@@ -0,0 +1,69 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: IKI
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ *
+ * These are provided for internal reduction in redundant code.
+ * These should not be exposed/used outside of this project.
+ */
+#ifndef _PRIVATE_F_iki_h
+#define _PRIVATE_F_iki_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Private implementation of f_iki_content_partial_is().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param buffer
+ *   The string to validate as an content name.
+ * @param range
+ *   The range within the buffer that represents the content name.
+ * @param quote
+ *   The quote character in use.
+ *   This must be either a single (') or double (") quote.
+ *
+ * @return
+ *   F_true on success and string is a valid content name.
+ *   F_false on success and string is not a valid content name.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see f_iki_content_is()
+ * @see f_iki_content_partial_is()
+ */
+#if !defined(_di_f_iki_content_is_) || !defined(_di_f_iki_content_partial_is_)
+  extern f_return_status private_f_iki_content_partial_is(const f_string_static_t buffer, const f_string_range_t range, const uint8_t quote) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_iki_content_is_) || !defined(_di_f_iki_content_partial_is_)
+
+/**
+ * Private implementation of f_iki_object_partial_is().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param buffer
+ *   The string to validate as an object name.
+ * @param range
+ *   The range within the buffer that represents the object name.
+ *
+ * @return
+ *   F_true on success and string is a valid object name.
+ *   F_false on success and string is not a valid object name.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see f_iki_object_is()
+ * @see f_iki_object_partial_is()
+ */
+#if !defined(_di_f_iki_object_is_) || !defined(_di_f_iki_object_partial_is_)
+  extern f_return_status private_f_iki_object_partial_is(const f_string_static_t buffer, const f_string_range_t range) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_iki_object_is_) || !defined(_di_f_iki_object_partial_is_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_F_iki_h
index 7e1f20aaed0c364e1d91ee03d5245a07ac807126..dce71cbdcfaf6aa3acd8f07320482f8d771ce2b3 100644 (file)
@@ -20,7 +20,7 @@ build_indexer ar
 build_language c
 build_libraries -lc
 build_libraries-individual -lf_utf -lf_memory
-build_sources_library iki.c
+build_sources_library iki.c private-iki.c
 build_sources_program
 build_sources_headers iki.h iki-common.h
 build_sources_script
diff --git a/level_2/fll_iki/c/iki.c b/level_2/fll_iki/c/iki.c
new file mode 100644 (file)
index 0000000..6f4e88f
--- /dev/null
@@ -0,0 +1,66 @@
+#include "iki.h"
+#include "private-iki.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_fll_iki_content_escape_
+  f_return_status fll_iki_content_escape(const f_string_static_t content, const uint8_t quote, f_string_dynamic_t *escaped) {
+    #ifndef _di_level_0_parameter_checking_
+      if (content.used > content.size) return F_status_set_error(F_parameter);
+      if (quote != f_iki_syntax_quote_single && quote != f_iki_syntax_quote_double) return F_status_set_error(F_parameter);
+      if (escaped->used > escaped->size) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    const f_string_range_t range = f_macro_string_range_t_initialize(content.used);
+
+    return private_fll_iki_content_partial_escape(content, range, quote, escaped);
+  }
+#endif // _di_fll_iki_content_escape_
+
+#ifndef _di_fll_iki_content_partial_escape_
+  f_return_status fll_iki_content_partial_escape(const f_string_static_t content, const f_string_range_t range, const uint8_t quote, f_string_dynamic_t *escaped) {
+    #ifndef _di_level_0_parameter_checking_
+      if (content.used > content.size) return F_status_set_error(F_parameter);
+      if (range.start > range.stop) return F_status_set_error(F_parameter);
+      if (range.start >= content.used) return F_status_set_error(F_parameter);
+      if (quote != f_iki_syntax_quote_single && quote != f_iki_syntax_quote_double) return F_status_set_error(F_parameter);
+      if (escaped->used > escaped->size) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    return private_fll_iki_content_partial_escape(content, range, quote, escaped);
+  }
+#endif // _di_fll_iki_content_partial_escape_
+
+#ifndef _di_fll_iki_content_escape_un_
+  f_return_status fll_iki_content_escape_un(const f_string_static_t content, const uint8_t quote, f_string_dynamic_t *unescaped) {
+    #ifndef _di_level_0_parameter_checking_
+      if (content.used > content.size) return F_status_set_error(F_parameter);
+      if (quote != f_iki_syntax_quote_single && quote != f_iki_syntax_quote_double) return F_status_set_error(F_parameter);
+      if (unescaped->used > unescaped->size) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    const f_string_range_t range = f_macro_string_range_t_initialize(content.used);
+
+    return private_fll_iki_content_partial_escape_un(content, range, quote, unescaped);
+  }
+#endif // _di_fll_iki_content_escape_un_
+
+#ifndef _di_fll_iki_content_partial_escape_un_
+  f_return_status fll_iki_content_partial_escape_un(const f_string_static_t content, const f_string_range_t range, const uint8_t quote, f_string_dynamic_t *unescaped) {
+    #ifndef _di_level_0_parameter_checking_
+      if (content.used > content.size) return F_status_set_error(F_parameter);
+      if (range.start > range.stop) return F_status_set_error(F_parameter);
+      if (range.start >= content.used) return F_status_set_error(F_parameter);
+      if (quote != f_iki_syntax_quote_single && quote != f_iki_syntax_quote_double) return F_status_set_error(F_parameter);
+      if (unescaped->used > unescaped->size) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    return private_fll_iki_content_partial_escape_un(content, range, quote, unescaped);
+  }
+#endif // _di_fll_iki_content_partial_escape_un_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_2/fll_iki/c/iki.h b/level_2/fll_iki/c/iki.h
new file mode 100644 (file)
index 0000000..82537ef
--- /dev/null
@@ -0,0 +1,147 @@
+/**
+ * FLL - Level 2
+ *
+ * Project: IKI
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ *
+ * Provides a Wiki-Like syntax meant to be much simpler.
+ *
+ * This simpler Wiki-Like syntax, called Iki, focuses just on simply adding context.
+ * The context itself is not explicitly defined but a few common standards are provided.
+ */
+#ifndef _FLL_iki_h
+#define _FLL_iki_h
+
+// libc includes
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.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/iki.h>
+
+// fll-1 includes
+#include <level_1/iki.h>
+#include <level_1/string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Escape a string to allow it to be used in its entirety as an IKI content.
+ *
+ * This does not copy NULL characters.
+ *
+ * @param content
+ *   The string to escape.
+ * @param quote
+ *   The quote character in use.
+ *   This must be either a single (') or double (") quote.
+ * @param escaped
+ *   The content whose data is escaped.
+ *   The escaped string data is appended to this, so set the escaped.used = 0 if "replace" behavior is desired.
+ *
+ * @return
+ *   F_none on success.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ *   Errors from (with error bit): f_macro_string_dynamic_t_resize().
+ *   Errors from (with error bit): fl_string_dynamic_size_increase().
+ */
+#ifndef _di_fll_iki_content_escape_
+  extern f_return_status fll_iki_content_escape(const f_string_static_t content, const uint8_t quote, f_string_dynamic_t *escaped);
+#endif // _di_fll_iki_content_escape_
+
+/**
+ * Escape a string, found within the given range, to allow it to be used in its entirety as an IKI content.
+ *
+ * This does not copy NULL characters.
+ *
+ * @param content
+ *   The string to escape.
+ * @param range
+ *   The range within the buffer that represents the content.
+ * @param quote
+ *   The quote character in use.
+ *   This must be either a single (') or double (") quote.
+ * @param escaped
+ *   The content whose data is escaped.
+ *   The escaped string data is appended to this, so set the escaped.used = 0 if "replace" behavior is desired.
+ *
+ * @return
+ *   F_none on success.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ *   Errors from (with error bit): f_macro_string_dynamic_t_resize().
+ *   Errors from (with error bit): fl_string_dynamic_size_increase().
+ */
+#ifndef _di_fll_iki_content_partial_escape_
+  extern f_return_status fll_iki_content_partial_escape(const f_string_static_t content, const f_string_range_t range, const uint8_t quote, f_string_dynamic_t *escaped);
+#endif // _di_fll_iki_content_partial_escape_
+
+/**
+ * Unescape a string from IKI content to allow it to be used normally.
+ *
+ * This does not copy NULL characters.
+ *
+ * @param content
+ *   The string to escape.
+ * @param quote
+ *   The quote character in use.
+ *   This must be either a single (') or double (") quote.
+ * @param unescaped
+ *   The content whose data is unescaped.
+ *   The unescaped string data is appended to this, so set the unescaped.used = 0 if "replace" behavior is desired.
+ *
+ * @return
+ *   F_none on success.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_syntax (with error bit) if the given string is invalid, such as having an undelimited quote.
+ *
+ *   Errors from (with error bit): f_macro_string_dynamic_t_resize().
+ *   Errors from (with error bit): fl_string_dynamic_size_increase().
+ */
+#ifndef _di_fll_iki_content_escape_un_
+  extern f_return_status fll_iki_content_escape_un(const f_string_static_t content, const uint8_t quote, f_string_dynamic_t *unescaped);
+#endif // _di_fll_iki_content_escape_un_
+
+/**
+ * Unescape a string, found within the given range, from IKI content to allow it to be used normally.
+ *
+ * This does not copy NULL characters.
+ *
+ * @param content
+ *   The string to escape.
+ * @param range
+ *   The range within the buffer that represents the content.
+ * @param quote
+ *   The quote character in use.
+ *   This must be either a single (') or double (") quote.
+ * @param unescaped
+ *   The content whose data is unescaped.
+ *   The unescaped string data is appended to this, so set the unescaped.used = 0 if "replace" behavior is desired.
+ *
+ * @return
+ *   F_none on success.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_syntax (with error bit) if the given string is invalid, such as having an undelimited quote.
+ *
+ *   Errors from (with error bit): f_macro_string_dynamic_t_resize().
+ *   Errors from (with error bit): fl_string_dynamic_size_increase().
+ */
+#ifndef _di_fll_iki_content_partial_escape_un_
+  extern f_return_status fll_iki_content_partial_escape_un(const f_string_static_t content, const f_string_range_t range, const uint8_t quote, f_string_dynamic_t *unescaped);
+#endif // _di_fll_iki_content_partial_escape_un_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _FLL_iki_h
diff --git a/level_2/fll_iki/c/private-iki.c b/level_2/fll_iki/c/private-iki.c
new file mode 100644 (file)
index 0000000..6e666f7
--- /dev/null
@@ -0,0 +1,190 @@
+#include "iki.h"
+#include "private-iki.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(_di_fll_iki_content_escape_) || !defined(_di_fll_iki_content_partial_escape_)
+  f_return_status private_fll_iki_content_partial_escape(const f_string_static_t content, const f_string_range_t range, const uint8_t quote, f_string_dynamic_t *escaped) {
+    f_status_t status = F_none;
+
+    // ensure escaped is at least the same size as content.
+    if (content.used > escaped->size) {
+      f_macro_string_dynamic_t_resize(status, (*escaped), content.used);
+      if (F_status_is_error(status)) return status;
+    }
+
+    f_string_length_t i = 0;
+    f_string_length_t j = 0;
+    f_string_length_t delimits = 0;
+
+    for (; i < content.used; i++) {
+
+      if (content.string[i] == quote) {
+        if (escaped->used + delimits + 2 > escaped->size) {
+          status = fl_string_dynamic_size_increase(delimits, escaped);
+          if (F_status_is_error(status)) return status;
+        }
+
+        for (j = 0; j < delimits; j++) {
+          escaped->string[escaped->used++] = f_iki_syntax_slash;
+        } // for
+
+        escaped->string[escaped->used++] = f_iki_syntax_slash;
+        escaped->string[escaped->used++] = quote;
+
+        delimits = 0;
+      }
+      else if (content.string[i]) {
+        if (escaped->used + 1 > escaped->size) {
+          status = fl_string_dynamic_size_increase(f_memory_default_allocation_step, escaped);
+          if (F_status_is_error(status)) return status;
+        }
+
+        if (content.string[i] == f_iki_syntax_slash) {
+          delimits++;
+        }
+        else {
+          delimits = 0;
+        }
+
+        escaped->string[escaped->used++] = content.string[i];
+      }
+    } // for
+
+    // delimits found at the end must be escaped to prevent escaping the end quote.
+    if (delimits) {
+      if (escaped->used + delimits > escaped->size) {
+        status = fl_string_dynamic_size_increase(delimits, escaped);
+        if (F_status_is_error(status)) return status;
+      }
+
+      for (j = 0; j < delimits; j++) {
+        escaped->string[escaped->used++] = f_iki_syntax_slash;
+      } // for
+    }
+
+    return F_none;
+  }
+#endif // !defined(_di_fll_iki_content_escape_) || !defined(_di_fll_iki_content_partial_escape_)
+
+#if !defined(_di_fll_iki_content_escape_un_) || !defined(_di_fll_iki_content_partial_escape_un_)
+  f_return_status private_fll_iki_content_partial_escape_un(const f_string_static_t content, const f_string_range_t range, const uint8_t quote, f_string_dynamic_t *unescaped) {
+    f_status_t status = F_none;
+
+    // ensure escaped is at least the same size as content.
+    if (content.used > unescaped->size) {
+      f_macro_string_dynamic_t_resize(status, (*unescaped), content.used);
+      if (F_status_is_error(status)) return status;
+    }
+
+    f_string_length_t i = 0;
+    f_string_length_t j = 0;
+    f_string_length_t delimits = 0;
+
+    const f_string_length_t used = unescaped->used;
+
+    for (; i < content.used; i++) {
+
+      if (content.string[i] == quote) {
+
+        // reset the used array on failure.
+        unescaped->used = used;
+
+        return F_status_set_error(F_syntax);
+      }
+      else if (content.string[i] == f_iki_syntax_slash) {
+        delimits = 1;
+
+        if (i + 1 < content.used) {
+          for (j = i + 1; j < content.used; j++) {
+
+            if (content.string[j] == quote) {
+              if (delimits % 2 == 0) {
+
+                // reset the used array on failure.
+                unescaped->used = used;
+
+                return F_status_set_error(F_syntax);
+              }
+
+              i = j;
+              delimits /= 2;
+
+              if (unescaped->used + delimits + 1 > unescaped->size) {
+                status = fl_string_dynamic_size_increase(delimits + 1, unescaped);
+                if (F_status_is_error(status)) return status;
+              }
+
+              for (j = 0; j < delimits; j++) {
+                unescaped->string[unescaped->used++] = f_iki_syntax_slash;
+              } // for
+
+              delimits = 0;
+              unescaped->string[unescaped->used++] = quote;
+              break;
+            }
+            else if (content.string[j] == f_iki_syntax_slash) {
+              delimits++;
+            }
+            else if (content.string[j]) {
+              if (unescaped->used + (j - i) + 1 > unescaped->size) {
+                status = fl_string_dynamic_size_increase((j - i) + 1, unescaped);
+                if (F_status_is_error(status)) return status;
+              }
+
+              for (; i <= j; i++) {
+                unescaped->string[unescaped->used++] = content.string[i];
+              } // for
+
+              delimits = 0;
+              i--;
+              break;
+            }
+          } // for
+        }
+
+        // at this point if delimits > 0, then this should be the end of the string.
+        if (delimits) {
+
+          // delimits at the end must be even to prevent escaping the closing quote.
+          if (delimits % 2) {
+
+            // reset the used array on failure.
+            unescaped->used = used;
+
+            return F_status_set_error(F_syntax);
+          }
+
+          delimits /= 2;
+
+          if (unescaped->used + delimits > unescaped->size) {
+            status = fl_string_dynamic_size_increase(delimits, unescaped);
+            if (F_status_is_error(status)) return status;
+          }
+
+          for (j = 0; j < delimits; j++) {
+            unescaped->string[unescaped->used++] = f_iki_syntax_slash;
+          } // for
+
+          break;
+        }
+      }
+      else if (content.string[i]) {
+        if (unescaped->used + 1 > unescaped->size) {
+          status = fl_string_dynamic_size_increase(f_memory_default_allocation_step, unescaped);
+          if (F_status_is_error(status)) return status;
+        }
+
+        unescaped->string[unescaped->used++] = content.string[i];
+      }
+    } // for
+
+    return F_none;
+  }
+#endif // !defined(_di_fll_iki_content_escape_un_) || !defined(_di_fll_iki_content_partial_escape_un_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_2/fll_iki/c/private-iki.h b/level_2/fll_iki/c/private-iki.h
new file mode 100644 (file)
index 0000000..9d8939a
--- /dev/null
@@ -0,0 +1,77 @@
+/**
+ * FLL - Level 2
+ *
+ * Project: IKI
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ *
+ * These are provided for internal reduction in redundant code.
+ * These should not be exposed/used outside of this project.
+ */
+#ifndef _PRIVATE_FLL_iki_h
+#define _PRIVATE_FLL_iki_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Private implementation of fll_iki_content_escape().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param content
+ *   The string to escape.
+ * @param range
+ *   The range within the buffer that represents the content.
+ * @param quote
+ *   The quote character in use.
+ *   This must be either a single (') or double (") quote.
+ * @param escaped
+ *   The content whose data is escaped.
+ *   The escaped string data is appended to this, so set the escaped.used = 0 if "replace" behavior is desired.
+ *
+ * @return
+ *   F_none on success.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ *   Errors from (with error bit): f_macro_string_dynamic_t_resize().
+ *   Errors from (with error bit): fl_string_dynamic_size_increase().
+ */
+#if !defined(_di_fll_iki_content_escape_) || !defined(_di_fll_iki_content_partial_escape_)
+  extern f_return_status private_fll_iki_content_partial_escape(const f_string_static_t content, const f_string_range_t range, const uint8_t quote, f_string_dynamic_t *escaped) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_fll_iki_content_escape_) || !defined(_di_fll_iki_content_partial_escape_)
+
+/**
+ * Private implementation of fll_iki_content_escape_un().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param content
+ *   The string to escape.
+ * @param range
+ *   The range within the buffer that represents the content.
+ * @param quote
+ *   The quote character in use.
+ *   This must be either a single (') or double (") quote.
+ * @param unescaped
+ *   The content whose data is unescaped.
+ *   The unescaped string data is appended to this, so set the unescaped.used = 0 if "replace" behavior is desired.
+ *
+ * @return
+ *   F_none on success.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_syntax (with error bit) if the given string is invalid, such as having an undelimited quote.
+ *
+ *   Errors from (with error bit): f_macro_string_dynamic_t_resize().
+ *   Errors from (with error bit): fl_string_dynamic_size_increase().
+ */
+#if !defined(_di_fll_iki_content_escape_un_) || !defined(_di_fll_iki_content_partial_escape_un_)
+  extern f_return_status private_fll_iki_content_partial_escape_un(const f_string_static_t content, const f_string_range_t range, const uint8_t quote, f_string_dynamic_t *unescaped) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_fll_iki_content_escape_un_) || !defined(_di_fll_iki_content_partial_escape_un_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_FLL_iki_h
diff --git a/level_2/fll_iki/data/build/defines b/level_2/fll_iki/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_2/fll_iki/data/build/dependencies b/level_2/fll_iki/data/build/dependencies
new file mode 100644 (file)
index 0000000..60e504d
--- /dev/null
@@ -0,0 +1,10 @@
+# fss-0000
+
+f_type
+f_status
+f_memory
+f_string
+f_utf
+f_iki
+fl_iki
+fl_string
diff --git a/level_2/fll_iki/data/build/settings b/level_2/fll_iki/data/build/settings
new file mode 100644 (file)
index 0000000..9ac1c02
--- /dev/null
@@ -0,0 +1,54 @@
+# fss-0001
+
+project_name fll_iki
+
+version_major 0
+version_minor 5
+version_micro 1
+version_target major
+
+environment
+
+process_pre
+process_post
+
+modes individual
+modes_default individual
+
+build_compiler gcc
+build_indexer ar
+build_language c
+build_libraries -lc
+build_libraries-individual -lfl_iki -lfl_string -lf_iki -lf_utf -lf_memory
+build_sources_library iki.c private-iki.c
+build_sources_program
+build_sources_headers iki.h
+build_sources_script
+build_sources_setting
+build_script yes
+build_shared yes
+build_static yes
+
+path_headers level_2
+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
+flags_shared
+flags_static
+flags_library -fPIC
+flags_program -fPIE
diff --git a/level_3/iki_write/c/iki_write.c b/level_3/iki_write/c/iki_write.c
new file mode 100644 (file)
index 0000000..87cf4bf
--- /dev/null
@@ -0,0 +1,343 @@
+#include "iki_write.h"
+#include "private-iki_write.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_iki_write_print_help_
+  f_return_status iki_write_print_help(const fl_color_context_t context) {
+    fll_program_print_help_header(context, iki_write_name_long, iki_write_version);
+
+    fll_program_print_help_option(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(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(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(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(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(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(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(context, iki_write_short_file, iki_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(context, iki_write_short_content, iki_write_long_content, f_console_symbol_short_enable, f_console_symbol_long_enable, "The content to write.");
+    fll_program_print_help_option(context, iki_write_short_double, iki_write_long_double, f_console_symbol_short_enable, f_console_symbol_long_enable, " Use double quotes (default).");
+    fll_program_print_help_option(context, iki_write_short_object, iki_write_long_object, f_console_symbol_short_enable, f_console_symbol_long_enable, " The object to write.");
+    fll_program_print_help_option(context, iki_write_short_single, iki_write_long_single, f_console_symbol_short_enable, f_console_symbol_long_enable, " Use single quotes.");
+
+    fll_program_print_help_usage(context, iki_write_name, "filename(s)");
+
+    fl_color_print(f_type_output, context.important, context.reset, " Notes:");
+
+    printf("%c", f_string_eol[0], f_string_eol[0]);
+
+    printf("  This program will accept object and content strings to generate an IKI string, such as: ");
+    fl_color_print(f_type_output, context.notable, context.reset, "object:\"content\"");
+    printf(".%c", f_string_eol[0]);
+
+    printf("  Each object must have a content (and each content must have an object).%c", f_string_eol[0]);
+
+    printf("%c", f_string_eol[0]);
+
+    printf("  When piping data to this program, a single end of line (\\n) must be used to separate each object from each content.%c", f_string_eol[0]);
+    printf("  Furthermore, each object must be followed by a content.%c", f_string_eol[0]);
+
+    printf("%c", f_string_eol[0]);
+
+    return F_none;
+  }
+#endif // _di_iki_write_print_help_
+
+#ifndef _di_iki_write_main_
+  f_return_status iki_write_main(const f_console_arguments_t arguments, iki_write_data_t *data) {
+    f_status_t status = F_none;
+
+    {
+      f_console_parameter_id_t ids[3] = { iki_write_parameter_no_color, iki_write_parameter_light, iki_write_parameter_dark };
+      const f_console_parameters_t parameters = { data->parameters, iki_write_total_parameters };
+      const f_console_parameter_ids_t choices = { ids, 3 };
+
+      status = fll_program_parameter_process(arguments, parameters, choices, F_true, &data->remaining, &data->context);
+      if (F_status_is_error(status)) {
+        iki_write_print_error(data->context, data->verbosity, F_status_set_fine(status), "fll_program_parameter_process", F_true);
+
+        if (data->verbosity == iki_write_verbosity_verbose) {
+          fprintf(f_type_error, "%c", f_string_eol[0]);
+        }
+
+        iki_write_delete_data(data);
+        return F_status_set_error(status);
+      }
+
+      status = F_none;
+    }
+
+    if (data->parameters[iki_write_parameter_help].result == f_console_result_found) {
+      iki_write_print_help(data->context);
+
+      iki_write_delete_data(data);
+      return status;
+    }
+    else if (data->parameters[iki_write_parameter_version].result == f_console_result_found) {
+      fll_program_print_version(iki_write_version);
+
+      iki_write_delete_data(data);
+      return status;
+    }
+
+    if (data->parameters[iki_write_parameter_verbose].result == f_console_result_found) {
+      if (data->parameters[iki_write_parameter_quiet].result == f_console_result_found) {
+        fprintf(f_type_error, "%c", f_string_eol[0]);
+        fl_color_print(f_type_error, data->context.error, data->context.reset, "ERROR: Cannot specify the '");
+        fl_color_print(f_type_error, data->context.notable, data->context.reset, "%s%s", f_console_symbol_long_enable, f_console_standard_long_verbose);
+        fl_color_print(f_type_error, data->context.error, data->context.reset, "' parameter with the '");
+        fl_color_print(f_type_error, data->context.notable, data->context.reset, "%s%s", f_console_symbol_long_enable, f_console_standard_long_quiet);
+        fl_color_print_line(f_type_error, data->context.error, data->context.reset, "' parameter.");
+
+        status = F_status_set_error(F_parameter);
+      }
+
+      data->verbosity = iki_write_verbosity_verbose;
+    }
+    else if (data->parameters[iki_write_parameter_quiet].result == f_console_result_found) {
+      data->verbosity = iki_write_verbosity_quiet;
+    }
+    else {
+      data->verbosity = iki_write_verbosity_normal;
+    }
+
+    if (!data->process_pipe) {
+      if (data->parameters[iki_write_parameter_object].result != f_console_result_additional && data->parameters[iki_write_parameter_content].result != f_console_result_additional) {
+        if (data->verbosity != iki_write_verbosity_quiet) {
+          fprintf(f_type_error, "%c", f_string_eol[0]);
+          fl_color_print(f_type_error, data->context.error, data->context.reset, "ERROR: No data provided, either pipe the data or use the '");
+          fl_color_print(f_type_error, data->context.notable, data->context.reset, "%s%s", f_console_symbol_long_enable, iki_write_long_object);
+          fl_color_print(f_type_error, data->context.error, data->context.reset, "' and the '");
+          fl_color_print(f_type_error, data->context.notable, data->context.reset, "%s%s", f_console_symbol_long_enable, iki_write_long_content);
+          fl_color_print_line(f_type_error, data->context.error, data->context.reset, "' parameters.");
+        }
+
+        status = F_status_set_error(F_parameter);
+      }
+    }
+
+    if (F_status_is_fine(status)) {
+      if (data->parameters[iki_write_parameter_object].additional.used != data->parameters[iki_write_parameter_content].additional.used) {
+        if (data->verbosity != iki_write_verbosity_quiet) {
+          fl_color_print(f_type_error, data->context.error, data->context.reset, "ERROR: The parameters '");
+          fl_color_print(f_type_error, data->context.notable, data->context.reset, "%s%s", f_console_symbol_long_enable, iki_write_long_content);
+          fl_color_print(f_type_error, data->context.error, data->context.reset, "' and '");
+          fl_color_print(f_type_error, data->context.notable, data->context.reset, "%s%s", f_console_symbol_long_enable, iki_write_long_object);
+          fl_color_print_line(f_type_error, data->context.error, data->context.reset, "' must be specified the same number of times.");
+        }
+
+        status = F_status_set_error(F_parameter);
+      }
+    }
+
+    uint8_t quote = f_iki_syntax_quote_double;
+
+    if (F_status_is_fine(status)) {
+      if (data->parameters[iki_write_parameter_double].result == f_console_result_found) {
+        if (data->parameters[iki_write_parameter_single].result == f_console_result_found) {
+          if (data->parameters[iki_write_parameter_double].location < data->parameters[iki_write_parameter_single].location) {
+            quote = f_iki_syntax_quote_single;
+          }
+        }
+      }
+      else if (data->parameters[iki_write_parameter_single].result == f_console_result_found) {
+        quote = f_iki_syntax_quote_single;
+      }
+    }
+
+    if (F_status_is_fine(status)) {
+      f_string_dynamic_t escaped = f_string_dynamic_t_initialize;
+
+      if (data->process_pipe) {
+        f_file_t file = f_file_t_initialize;
+
+        file.id = f_type_descriptor_input;
+        file.size_read = 1;
+
+        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;
+
+        bool object_ended = F_false;
+
+        f_string_length_t previous = 0;
+        f_string_range_t range = f_string_range_t_initialize;
+
+        range.start = 0;
+
+        for (f_status_t status_pipe = F_none; ; ) {
+
+          if (status_pipe != F_none_eof) {
+            status_pipe = f_file_read(file, &buffer);
+
+            if (F_status_is_error(status_pipe)) {
+              iki_write_print_error_file(data->context, data->verbosity, F_status_set_fine(status_pipe), "f_file_read_to", "-", "read", 2, F_true);
+
+              status = F_status_set_error(F_pipe);
+              break;
+            }
+
+            if (!buffer.used) {
+              if (data->verbosity != iki_write_verbosity_quiet) {
+                fl_color_print_line(f_type_error, data->context.error, data->context.reset, "ERROR: The pipe has no content.");
+              }
+
+              status = F_status_set_error(F_parameter);
+              break;
+            }
+
+            range.stop = buffer.used - 1;
+          }
+
+          previous = range.start;
+          status = fl_string_dynamic_seek_line(buffer.string, &range);
+
+          if (F_status_is_error(status)) {
+            iki_write_print_error(data->context, data->verbosity, F_status_set_fine(status), "fl_string_dynamic_seek_line", F_true);
+            break;
+          }
+
+          if (status == F_data_not_stop) {
+            status = F_status_set_error(F_parameter);
+            iki_write_print_error(data->context, data->verbosity, F_parameter, "fl_string_dynamic_seek_line", F_true);
+            break;
+          }
+
+          if (object_ended && previous == range.start) {
+            if (data->verbosity != iki_write_verbosity_quiet) {
+              fl_color_print_line(f_type_error, data->context.error, data->context.reset, "ERROR: The pipe has incorrectly placed newlines.");
+            }
+
+            status = F_status_set_error(F_parameter);
+            break;
+          }
+
+          range.stop = range.start - 1;
+          range.start = previous;
+
+          if (object_ended) {
+            content.used = 0;
+
+            if (buffer.used) {
+              status = fl_string_dynamic_partial_append_nulless(buffer, range, &content);
+
+              if (F_status_is_error(status)) {
+                iki_write_print_error(data->context, data->verbosity, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true);
+                break;
+              }
+            }
+
+            status = iki_write_process(*data, object, content, quote, f_type_output, &escaped);
+            if (F_status_is_error(status)) break;
+
+            fprintf(f_type_output, "%c", f_string_eol[0]);
+
+            object_ended = F_false;
+          }
+          else {
+            object.used = 0;
+
+            status = fl_string_dynamic_partial_append_nulless(buffer, range, &object);
+
+            if (F_status_is_error(status)) {
+              iki_write_print_error(data->context, data->verbosity, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true);
+              break;
+            }
+
+            object_ended = F_true;
+          }
+
+          // restore the range, positioned after the newline.
+          range.start = range.stop + 2;
+          range.stop = buffer.used - 1;
+
+          // only clear the buffer and reset the start when the entire buffer has been processed.
+          if (range.start > range.stop) {
+            range.start = 0;
+            buffer.used = 0;
+          }
+
+          if (status_pipe == F_none_eof && !buffer.used && !object_ended) break;
+        } // for
+
+        if (F_status_is_fine(status) && object_ended) {
+          if (data->verbosity != iki_write_verbosity_quiet) {
+            fl_color_print_line(f_type_error, data->context.error, data->context.reset, "ERROR: The pipe has an object without content.");
+          }
+
+          status = F_status_set_error(F_parameter);
+        }
+
+        f_macro_string_dynamic_t_delete_simple(buffer);
+        f_macro_string_dynamic_t_delete_simple(object);
+        f_macro_string_dynamic_t_delete_simple(content);
+      }
+
+      if (F_status_is_fine(status)) {
+        f_string_static_t object = f_string_static_t_initialize;
+        f_string_static_t content = f_string_static_t_initialize;
+
+        for (f_array_length_t i = 0; i < data->parameters[iki_write_parameter_object].additional.used; i++) {
+
+          object.string = arguments.argv[data->parameters[iki_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[iki_write_parameter_content].additional.array[i]];
+          content.used = strnlen(content.string, f_console_length_size);
+          content.size = content.used;
+
+          status = iki_write_process(*data, object, content, quote, f_type_output, &escaped);
+          if (F_status_is_error(status)) break;
+
+          fprintf(f_type_output, "%c", f_string_eol[0]);
+        } // for
+
+        // ensure there is always a newline at the end, unless in quiet mode.
+        if (F_status_is_fine(status) && data->verbosity != iki_write_verbosity_quiet) {
+          fprintf(f_type_output, "%c", f_string_eol[0]);
+        }
+      }
+
+      f_macro_string_dynamic_t_delete_simple(escaped);
+    }
+
+    // ensure a newline is always put at the end of the program execution, unless in quiet mode.
+    if (data->verbosity != iki_write_verbosity_quiet) {
+      if (F_status_is_error(status)) {
+        fprintf(f_type_error, "%c", f_string_eol[0]);
+      }
+    }
+
+    iki_write_delete_data(data);
+    return status;
+  }
+#endif // _di_iki_write_main_
+
+#ifndef _di_iki_write_delete_data_
+  f_return_status iki_write_delete_data(iki_write_data_t *data) {
+    f_status_t status = F_none;
+    f_string_length_t i = 0;
+
+    while (i < iki_write_total_parameters) {
+      f_macro_string_lengths_t_delete_simple(data->parameters[i].locations);
+      f_macro_string_lengths_t_delete_simple(data->parameters[i].additional);
+      i++;
+    } // while
+
+    f_macro_string_lengths_t_delete_simple(data->remaining);
+    f_macro_string_dynamic_t_delete_simple(data->buffer);
+    fl_macro_color_context_t_delete_simple(data->context);
+
+    return F_none;
+  }
+#endif // _di_iki_write_delete_data_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_3/iki_write/c/iki_write.h b/level_3/iki_write/c/iki_write.h
new file mode 100644 (file)
index 0000000..becd244
--- /dev/null
@@ -0,0 +1,202 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: IKI
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ *
+ * This is the IKI Write program.
+ *
+ * This program utilizes the Featureless Linux Library.
+ * This program processes files or other input in fss format and stores the results in the iki_write_data_t.
+ *
+ * This processes in accordance to the IKI specification.
+ */
+#ifndef _iki_write_h
+
+// libc includes
+#include <dirent.h>
+#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/conversion.h>
+#include <level_0/file.h>
+#include <level_0/iki.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/conversion.h>
+#include <level_1/iki.h>
+#include <level_1/print.h>
+#include <level_1/string.h>
+
+// fll-2 includes
+#include <level_2/file.h>
+#include <level_2/iki.h>
+#include <level_2/program.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_iki_write_version_
+  #define iki_write_major_version "0"
+  #define iki_write_minor_version "5"
+  #define iki_write_micro_version "1"
+  #define iki_write_version iki_write_major_version "." iki_write_minor_version "." iki_write_micro_version
+#endif // _di_iki_write_version_
+
+#ifndef _di_iki_write_name_
+  #define iki_write_name      "iki_write"
+  #define iki_write_name_long "IKI Write"
+#endif // _di_iki_write_name_
+
+#ifndef _di_iki_write_defines_
+  enum {
+    iki_write_verbosity_quiet = 1,
+    iki_write_verbosity_normal,
+    iki_write_verbosity_verbose,
+    iki_write_verbosity_debug,
+  };
+
+  #define iki_write_short_file    "f"
+  #define iki_write_short_content "c"
+  #define iki_write_short_double  "d"
+  #define iki_write_short_object  "o"
+  #define iki_write_short_single  "s"
+
+  #define iki_write_long_file    "file"
+  #define iki_write_long_content "content"
+  #define iki_write_long_double  "double"
+  #define iki_write_long_object  "object"
+  #define iki_write_long_single  "single"
+
+  enum {
+    iki_write_parameter_help,
+    iki_write_parameter_light,
+    iki_write_parameter_dark,
+    iki_write_parameter_no_color,
+    iki_write_parameter_quiet,
+    iki_write_parameter_verbose,
+    iki_write_parameter_version,
+
+    iki_write_parameter_file,
+    iki_write_parameter_content,
+    iki_write_parameter_double,
+    iki_write_parameter_object,
+    iki_write_parameter_single,
+  };
+
+  #define iki_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, 0, f_console_type_inverse), \
+      f_console_parameter_t_initialize(f_console_standard_short_quiet, f_console_standard_long_quiet, 0, 0, f_console_type_inverse), \
+      f_console_parameter_t_initialize(f_console_standard_short_verbose, f_console_standard_long_verbose, 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(iki_write_short_file, iki_write_long_file, 0, 1, f_console_type_normal), \
+      f_console_parameter_t_initialize(iki_write_short_content, iki_write_long_content, 0, 1, f_console_type_normal), \
+      f_console_parameter_t_initialize(iki_write_short_double, iki_write_long_double, 0, 0, f_console_type_normal), \
+      f_console_parameter_t_initialize(iki_write_short_object, iki_write_long_object, 0, 1, f_console_type_normal), \
+      f_console_parameter_t_initialize(iki_write_short_single, iki_write_long_single, 0, 0, f_console_type_normal), \
+    }
+
+  #define iki_write_total_parameters 12
+#endif // _di_iki_write_defines_
+
+#ifndef _di_iki_write_data_t_
+  typedef struct {
+    f_console_parameter_t parameters[iki_write_total_parameters];
+
+    f_string_lengths_t remaining;
+    bool process_pipe;
+
+    uint8_t verbosity;
+
+    f_string_dynamic_t buffer;
+
+    fl_color_context_t context;
+  } iki_write_data_t;
+
+  #define iki_write_data_t_initialize \
+    { \
+      iki_write_console_parameter_t_initialize, \
+      f_string_lengths_t_initialize, \
+      F_false, \
+      0, \
+      f_string_dynamic_t_initialize, \
+      fl_color_context_t_initialize, \
+    }
+#endif // _di_iki_write_data_t_
+
+/**
+ * Print help to standard output.
+ *
+ * @param context
+ *   The color context settings.
+ *
+ * @return
+ *   F_none on success.
+ */
+#ifndef _di_iki_write_print_help_
+  extern f_return_status iki_write_print_help(const fl_color_context_t context);
+#endif // _di_iki_write_print_help_
+
+/**
+ * Execute main program.
+ *
+ * Be sure to call iki_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 iki_write_delete_data()
+ */
+#ifndef _di_iki_write_main_
+  extern f_return_status iki_write_main(const f_console_arguments_t arguments, iki_write_data_t *data);
+#endif // _di_iki_write_main_
+
+/**
+ * Deallocate data.
+ *
+ * Be sure to call this after executing iki_write_main().
+ *
+ * @param data
+ *   The program data.
+ *
+ * @return
+ *   F_none on success.
+ *
+ *   Status codes (with error bit) are returned on any problem.
+ *
+ * @see iki_write_main()
+ */
+#ifndef _di_iki_write_delete_data_
+  extern f_return_status iki_write_delete_data(iki_write_data_t *data);
+#endif // _di_iki_write_delete_data_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _iki_write_h
diff --git a/level_3/iki_write/c/main.c b/level_3/iki_write/c/main.c
new file mode 100644 (file)
index 0000000..1ef60bc
--- /dev/null
@@ -0,0 +1,18 @@
+#include "iki_write.h"
+
+int main(const unsigned long argc, const f_string_t *argv) {
+  const f_console_arguments_t arguments = { argc, argv };
+  iki_write_data_t data = iki_write_data_t_initialize;
+
+  if (f_pipe_input_exists()) {
+    data.process_pipe = F_true;
+  }
+
+  f_status_t status = iki_write_main(arguments, &data);
+
+  if (F_status_is_error(status)) {
+    return 1;
+  }
+
+  return 0;
+}
diff --git a/level_3/iki_write/c/private-iki_write.c b/level_3/iki_write/c/private-iki_write.c
new file mode 100644 (file)
index 0000000..7d5eea1
--- /dev/null
@@ -0,0 +1,328 @@
+#include "iki_write.h"
+#include "private-iki_write.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_iki_write_print_error_
+  f_return_status iki_write_print_error(const fl_color_context_t context, const uint8_t verbosity, const f_status_t status, const f_string_t function, const bool fallback) {
+
+    if (status == F_parameter) {
+      if (verbosity != iki_write_verbosity_quiet) {
+        fprintf(f_type_error, "%c", f_string_eol[0]);
+        fl_color_print(f_type_error, context.error, context.reset, "ERROR: Invalid parameter when calling function ");
+        fl_color_print(f_type_error, context.notable, context.reset, "%s", function);
+        fl_color_print_line(f_type_error, context.error, context.reset, "().");
+      }
+
+      return F_none;
+    }
+
+    if (status == F_memory_allocation || status == F_memory_reallocation) {
+      if (verbosity != iki_write_verbosity_quiet) {
+        fprintf(f_type_error, "%c", f_string_eol[0]);
+        fl_color_print(f_type_error, context.error, context.reset, "ERROR: Unable to allocate memory in function ");
+        fl_color_print(f_type_error, context.notable, context.reset, "%s", function);
+        fl_color_print_line(f_type_error, context.error, context.reset, "().");
+      }
+
+      return F_none;
+    }
+
+    if (status == F_buffer_too_large) {
+      if (verbosity != iki_write_verbosity_quiet) {
+        fprintf(f_type_error, "%c", f_string_eol[0]);
+        fl_color_print(f_type_error, context.error, context.reset, "ERROR: Maximum buffer limit reached while processing ");
+        fl_color_print(f_type_error, context.notable, context.reset, "%s", function);
+        fl_color_print_line(f_type_error, context.error, context.reset, "().");
+      }
+
+      return F_none;
+    }
+
+    if (status == F_string_too_large) {
+      if (verbosity != iki_write_verbosity_quiet) {
+        fprintf(f_type_error, "%c", f_string_eol[0]);
+        fl_color_print(f_type_error, context.error, context.reset, "ERROR: Maximum string limit reached while processing ");
+        fl_color_print(f_type_error, context.notable, context.reset, "%s", function);
+        fl_color_print_line(f_type_error, context.error, context.reset, "().");
+      }
+
+      return F_none;
+    }
+
+    if (fallback && verbosity != iki_write_verbosity_quiet) {
+      fprintf(f_type_error, "%c", f_string_eol[0]);
+      fl_color_print(f_type_error, context.error, context.reset, "UNKNOWN ERROR: (");
+      fl_color_print(f_type_error, context.notable, context.reset, "%llu", status);
+      fl_color_print(f_type_error, context.error, context.reset, ") in function ");
+      fl_color_print(f_type_error, context.notable, context.reset, "%s", function);
+      fl_color_print_line(f_type_error, context.error, context.reset, "().");
+    }
+
+    return F_unknown;
+  }
+#endif // _di_iki_write_print_error_
+
+#ifndef _di_iki_write_print_error_file_
+  bool iki_write_print_error_file(const fl_color_context_t context, const uint8_t verbosity, const f_status_t status, const f_string_t function, const f_string_t name, const f_string_t operation, const uint8_t type, const bool fallback) {
+    f_string_t type_name = "file";
+
+    if (type == 1) {
+      type_name = "directory";
+    }
+    else if (type == 2) {
+      type_name = "pipe";
+    }
+
+    if (status == F_file_found_not) {
+      if (verbosity != iki_write_verbosity_quiet) {
+        fprintf(f_type_error, "%c", f_string_eol[0]);
+        fl_color_print(f_type_error, context.error, context.reset, "ERROR: Failed to find %s '", type_name);
+        fl_color_print(f_type_error, context.notable, context.reset, "%s", name);
+        fl_color_print_line(f_type_error, context.error, context.reset, "'.");
+      }
+
+      return F_false;
+    }
+
+    if (status == F_file_closed) {
+      if (verbosity != iki_write_verbosity_quiet) {
+        fl_color_print(f_type_error, context.error, context.reset, "INTERNAL ERROR: The %s '", type_name);
+        fl_color_print(f_type_error, context.notable, context.reset, "%s", name);
+        fl_color_print_line(f_type_error, context.error, context.reset, "' is no longer open.");
+      }
+
+      return F_false;
+    }
+
+    if (status == F_file_seek) {
+      if (verbosity != iki_write_verbosity_quiet) {
+        fl_color_print(f_type_error, context.error, context.reset, "ERROR: A seek error occurred while accessing the file '");
+        fl_color_print(f_type_error, context.notable, context.reset, "%s", name);
+        fl_color_print_line(f_type_error, context.error, context.reset, "'.");
+      }
+
+      return F_false;
+    }
+
+    if (status == F_file_read) {
+      if (verbosity != iki_write_verbosity_quiet) {
+        fl_color_print(f_type_error, context.error, context.reset, "ERROR: A read error occurred while accessing the file '");
+        fl_color_print(f_type_error, context.notable, context.reset, "%s", name);
+        fl_color_print_line(f_type_error, context.error, context.reset, "'.");
+      }
+
+      return F_false;
+    }
+
+    if (status == F_file_found) {
+      if (verbosity != iki_write_verbosity_quiet) {
+        fprintf(f_type_error, "%c", f_string_eol[0]);
+        fl_color_print(f_type_error, context.error, context.reset, "ERROR: The %s '", type_name);
+        fl_color_print(f_type_error, context.notable, context.reset, "%s", name);
+        fl_color_print_line(f_type_error, context.error, context.reset, "' already exists.");
+      }
+
+      return F_false;
+    }
+
+    if (status == F_parameter) {
+      if (verbosity != iki_write_verbosity_quiet) {
+        fprintf(f_type_error, "%c", f_string_eol[0]);
+        fl_color_print(f_type_error, context.error, context.reset, "INTERNAL ERROR: Invalid parameter when calling ");
+        fl_color_print(f_type_error, context.notable, context.reset, "%s", function);
+        fl_color_print(f_type_error, context.error, context.reset, "() for the %s '", type_name);
+        fl_color_print(f_type_error, context.notable, context.reset, "%s", name);
+        fl_color_print_line(f_type_error, context.error, context.reset, "'.");
+      }
+
+      return F_false;
+    }
+
+    if (status == F_name) {
+      if (verbosity != iki_write_verbosity_quiet) {
+        fprintf(f_type_error, "%c", f_string_eol[0]);
+        fl_color_print(f_type_error, context.error, context.reset, "ERROR: Invalid %s name '", type_name);
+        fl_color_print(f_type_error, context.notable, context.reset, "%s", name);
+        fl_color_print_line(f_type_error, context.error, context.reset, "'.");
+      }
+
+      return F_false;
+    }
+
+    if (status == F_memory_out) {
+      if (verbosity != iki_write_verbosity_quiet) {
+        fprintf(f_type_error, "%c", f_string_eol[0]);
+        fl_color_print(f_type_error, context.error, context.reset, "CRITICAL ERROR: Unable to allocate memory, while trying to %s %s '", operation, type_name);
+        fl_color_print(f_type_error, context.notable, context.reset, "%s", name);
+        fl_color_print_line(f_type_error, context.error, context.reset, "'.");
+      }
+
+      return F_false;
+    }
+
+    if (status == F_number_overflow) {
+      if (verbosity != iki_write_verbosity_quiet) {
+        fprintf(f_type_error, "%c", f_string_eol[0]);
+        fl_color_print(f_type_error, context.error, context.reset, "ERROR: Overflow while trying to %s %s '", operation, type_name);
+        fl_color_print(f_type_error, context.notable, context.reset, "%s", name);
+        fl_color_print_line(f_type_error, context.error, context.reset, "'.");
+      }
+
+      return F_false;
+    }
+
+    if (status == F_directory) {
+      if (verbosity != iki_write_verbosity_quiet) {
+        fprintf(f_type_error, "%c", f_string_eol[0]);
+        fl_color_print(f_type_error, context.error, context.reset, "ERROR: Invalid directory while trying to %s %s '", operation, type_name);
+        fl_color_print(f_type_error, context.notable, context.reset, "%s", name);
+        fl_color_print_line(f_type_error, context.error, context.reset, "'.");
+      }
+
+      return F_false;
+    }
+
+    if (status == F_access_denied) {
+      if (verbosity != iki_write_verbosity_quiet) {
+        fprintf(f_type_error, "%c", f_string_eol[0]);
+        fl_color_print(f_type_error, context.error, context.reset, "ERROR: Access denied while trying to %s %s '", operation, type_name);
+        fl_color_print(f_type_error, context.notable, context.reset, "%s", name);
+        fl_color_print_line(f_type_error, context.error, context.reset, "'.");
+      }
+
+      return F_false;
+    }
+
+    if (status == F_loop) {
+      if (verbosity != iki_write_verbosity_quiet) {
+        fprintf(f_type_error, "%c", f_string_eol[0]);
+        fl_color_print(f_type_error, context.error, context.reset, "ERROR: Loop while trying to %s %s '", operation, type_name);
+        fl_color_print(f_type_error, context.notable, context.reset, "%s", name);
+        fl_color_print_line(f_type_error, context.error, context.reset, "'.");
+      }
+
+      return F_false;
+    }
+
+    if (status == F_prohibited) {
+      if (verbosity != iki_write_verbosity_quiet) {
+        fprintf(f_type_error, "%c", f_string_eol[0]);
+        fl_color_print(f_type_error, context.error, context.reset, "ERROR: Prohibited by system while trying to %s %s '", operation, type_name);
+        fl_color_print(f_type_error, context.notable, context.reset, "%s", name);
+        fl_color_print_line(f_type_error, context.error, context.reset, "'.");
+      }
+
+      return F_false;
+    }
+
+    if (!type) {
+      if (status == F_directory_found_not) {
+        if (verbosity != iki_write_verbosity_quiet) {
+          fprintf(f_type_error, "%c", f_string_eol[0]);
+          fl_color_print(f_type_error, context.error, context.reset, "ERROR: Failed to %s %s '", operation, type_name);
+          fl_color_print(f_type_error, context.notable, context.reset, "%s", name);
+          fl_color_print_line(f_type_error, context.error, context.reset, "' due to an invalid directory in the path.");
+        }
+
+        return F_false;
+      }
+    }
+    else if (type == 1) {
+      if (status == F_directory_found_not) {
+        if (verbosity != iki_write_verbosity_quiet) {
+          fprintf(f_type_error, "%c", f_string_eol[0]);
+          fl_color_print(f_type_error, context.error, context.reset, "ERROR: Failed to %s %s '", operation, type_name);
+          fl_color_print(f_type_error, context.notable, context.reset, "%s", name);
+          fl_color_print_line(f_type_error, context.error, context.reset, "' due to an invalid directory in the path.");
+        }
+
+        return F_false;
+      }
+
+      if (status == F_failure) {
+        if (verbosity != iki_write_verbosity_quiet) {
+          fprintf(f_type_error, "%c", f_string_eol[0]);
+          fl_color_print(f_type_error, context.error, context.reset, "ERROR: Failed to %s %s '", operation, type_name);
+          fl_color_print(f_type_error, context.notable, context.reset, "%s", name);
+          fl_color_print_line(f_type_error, context.error, context.reset, "'.");
+        }
+
+        return F_false;
+      }
+    }
+
+    if (iki_write_print_error(context, verbosity, status, function, F_false) == F_unknown && fallback && verbosity != iki_write_verbosity_quiet) {
+      fprintf(f_type_error, "%c", f_string_eol[0]);
+      fl_color_print(f_type_error, context.error, context.reset, "UNKNOWN ERROR: (");
+      fl_color_print(f_type_error, context.notable, context.reset, "%llu", status);
+      fl_color_print(f_type_error, context.error, context.reset, ") occurred while trying to %s %s '", operation, type_name);
+      fl_color_print(f_type_error, context.notable, context.reset, "%s", name);
+      fl_color_print_line(f_type_error, context.error, context.reset, "'.");
+    }
+
+    return F_true;
+  }
+#endif // _di_iki_write_print_error_file_
+
+#ifndef _di_iki_write_process_
+  f_return_status iki_write_process(const iki_write_data_t data, const f_string_static_t object, const f_string_static_t content, const uint8_t quote, FILE *output, f_string_dynamic_t *escaped) {
+
+    if (!object.used) {
+      if (data.verbosity != iki_write_verbosity_quiet) {
+        fprintf(f_type_error, "%c", f_string_eol[0]);
+        fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: The object is missing, it must not have a length of ");
+        fl_color_print(f_type_error, data.context.notable, data.context.reset, "0");
+        fl_color_print_line(f_type_error, data.context.error, data.context.reset, ".");
+      }
+
+      return F_status_set_error(F_failure);
+    }
+
+    f_status_t status = f_iki_object_is(object);
+
+    if (status == F_false) {
+      if (data.verbosity != iki_write_verbosity_quiet) {
+        fprintf(f_type_error, "%c", f_string_eol[0]);
+        fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: The object '");
+
+        fl_color_print_code(f_type_error, data.context.notable);
+        f_print_string_dynamic(f_type_error, object);
+        fl_color_print_code(f_type_error, data.context.reset);
+
+        fl_color_print_line(f_type_error, data.context.error, data.context.reset, "' is not a valid IKI object.");
+      }
+
+      return F_status_set_error(F_failure);
+    }
+    else if (F_status_is_error(status)) {
+      iki_write_print_error(data.context, data.verbosity, F_status_set_fine(status), "f_iki_object_is", F_true);
+
+      return F_status_set_error(F_failure);
+    }
+
+    escaped->used = 0;
+
+    status = fll_iki_content_escape(content, quote, escaped);
+
+    if (F_status_is_error(status)) {
+      iki_write_print_error(data.context, data.verbosity, F_status_set_fine(status), "fll_iki_content_escape", F_true);
+
+      f_macro_string_dynamic_t_delete_simple((*escaped));
+      return F_status_set_error(F_failure);
+    }
+
+    f_print_string_dynamic(output, object);
+    fprintf(output, "%c%c", f_iki_syntax_separator, quote);
+    f_print_string_dynamic(output, *escaped);
+    fprintf(output, "%c", quote);
+
+    return F_none;
+  }
+#endif // _di_iki_write_process_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_3/iki_write/c/private-iki_write.h b/level_3/iki_write/c/private-iki_write.h
new file mode 100644 (file)
index 0000000..d1fec29
--- /dev/null
@@ -0,0 +1,94 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: FSS
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ */
+#ifndef _PRIVATE_iki_write_h
+#define _PRIVATE_iki_write_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Print generic error messages.
+ *
+ * @param context
+ *   The color context.
+ * @param verbosity
+ *   The verbosity level, which determines if and what should be printed.
+ * @param status
+ *   The status code representing an error.
+ * @param function
+ *   The name of the function where the error happened.
+ * @param fallback
+ *   Set to F_true to print the fallback error message for unknown errors.
+ *
+ * @return
+ *   F_none is returned on successful print of known errors.
+ *   F_unknown is returned if the status code has no print message.
+ */
+#ifndef _di_iki_write_print_error_
+  extern f_return_status iki_write_print_error(const fl_color_context_t context, const uint8_t verbosity, const f_status_t status, const f_string_t function, const bool fallback) f_gcc_attribute_visibility_internal;
+#endif // _di_iki_write_print_error_
+
+/**
+ * Print file/directory error messages.
+ *
+ * @param context
+ *   The color context.
+ * @param verbosity
+ *   The verbosity level, which determines if and what should be printed.
+ * @param status
+ *   The error status code to report on.
+ * @param function
+ *   The function call that returned the error.
+ * @param name
+ *   The name of the file or directory.
+ * @param operation
+ *   The operation that fails, such as 'create' or 'access'.
+ * @param type
+ *   Set to 0 for "file", 1 for "directory", and 2 for "pipe".
+ * @param fallback
+ *   Set to F_true to print the fallback error message for unknown errors.
+ *
+ * @return
+ *   F_true is returned if the status code has no print message.
+ *   F_false is returned on successful print of known errors.
+ */
+#ifndef _di_iki_write_print_error_file_
+  extern bool iki_write_print_error_file(const fl_color_context_t context, const uint8_t verbosity, const f_status_t status, const f_string_t function, const f_string_t name, const f_string_t operation, const uint8_t type, const bool fallback) f_gcc_attribute_visibility_internal;
+#endif // _di_iki_write_print_error_file_
+
+/**
+ * Process a given object and content, printing the IKI if valid or an error if invalid.
+ *
+ * @param data
+ *   The program data.
+ * @param object
+ *   The object to validate and print.
+ * @param content
+ *   The content to escape and print.
+ * @param quote
+ *   The quote character to use.
+ *   This is either f_iki_syntax_quote_single or f_iki_syntax_quote_double.
+ * @param output
+ *   The output file (or stdout) to print to.
+ * @param escaped
+ *   A string buffer used as a string cache to save the string into while escaping.
+ *
+ * @return
+ *   F_none on success.
+ *   F_failure (with error bit) for any othe failure.
+ */
+#ifndef _di_iki_write_process_
+  extern f_return_status iki_write_process(const iki_write_data_t data, const f_string_static_t object, const f_string_static_t content, const uint8_t quote, FILE *output, f_string_dynamic_t *escaped) f_gcc_attribute_visibility_internal;
+#endif // _di_iki_write_process_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_iki_write_h
diff --git a/level_3/iki_write/data/build/defines b/level_3/iki_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/iki_write/data/build/dependencies b/level_3/iki_write/data/build/dependencies
new file mode 100644 (file)
index 0000000..7f74885
--- /dev/null
@@ -0,0 +1,23 @@
+# fss-0000
+
+f_type
+f_status
+f_memory
+f_string
+f_utf
+f_color
+f_console
+f_conversion
+f_file
+f_iki
+f_pipe
+f_print
+fl_color
+fl_console
+fl_conversion
+fl_iki
+fl_string
+fl_utf
+fll_file
+fll_iki
+fll_program
diff --git a/level_3/iki_write/data/build/settings b/level_3/iki_write/data/build/settings
new file mode 100644 (file)
index 0000000..e7f026e
--- /dev/null
@@ -0,0 +1,56 @@
+# fss-0001
+
+project_name iki_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_iki -lfll_file -lfl_directory -lf_path -lf_directory -lfl_utf -lfl_string -lfl_iki -lfl_conversion -lfl_console -lfl_color -lf_print -lf_pipe -lf_iki -lf_file -lf_conversion -lf_console -lf_utf -lf_memory
+build_libraries-level -lfll_2 -lfll_1 -lfll_0
+build_libraries-monolithic -lfll
+build_sources_library iki_write.c private-iki_write.c
+build_sources_program main.c
+build_sources_headers iki_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