From 3115127d096114ca0cbd766bb19511fa89d615a7 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Fri, 18 Sep 2020 19:39:05 -0500 Subject: [PATCH] Feature: add iki_write and all related dependencies. --- build/level_0/settings | 2 +- build/level_2/settings | 4 +- build/monolithic/settings | 4 +- build/scripts/bootstrap-example.sh | 2 +- level_0/f_iki/c/iki.c | 55 ++++- level_0/f_iki/c/iki.h | 74 +++++++ level_0/f_iki/c/private-iki.c | 52 +++++ level_0/f_iki/c/private-iki.h | 69 ++++++ level_0/f_iki/data/build/settings | 2 +- level_2/fll_iki/c/iki.c | 66 ++++++ level_2/fll_iki/c/iki.h | 147 +++++++++++++ level_2/fll_iki/c/private-iki.c | 190 +++++++++++++++++ level_2/fll_iki/c/private-iki.h | 77 +++++++ level_2/fll_iki/data/build/defines | 2 + level_2/fll_iki/data/build/dependencies | 10 + level_2/fll_iki/data/build/settings | 54 +++++ level_3/iki_write/c/iki_write.c | 343 ++++++++++++++++++++++++++++++ level_3/iki_write/c/iki_write.h | 202 ++++++++++++++++++ level_3/iki_write/c/main.c | 18 ++ level_3/iki_write/c/private-iki_write.c | 328 ++++++++++++++++++++++++++++ level_3/iki_write/c/private-iki_write.h | 94 ++++++++ level_3/iki_write/data/build/defines | 2 + level_3/iki_write/data/build/dependencies | 23 ++ level_3/iki_write/data/build/settings | 56 +++++ 24 files changed, 1867 insertions(+), 9 deletions(-) create mode 100644 level_0/f_iki/c/private-iki.c create mode 100644 level_0/f_iki/c/private-iki.h create mode 100644 level_2/fll_iki/c/iki.c create mode 100644 level_2/fll_iki/c/iki.h create mode 100644 level_2/fll_iki/c/private-iki.c create mode 100644 level_2/fll_iki/c/private-iki.h create mode 100644 level_2/fll_iki/data/build/defines create mode 100644 level_2/fll_iki/data/build/dependencies create mode 100644 level_2/fll_iki/data/build/settings create mode 100644 level_3/iki_write/c/iki_write.c create mode 100644 level_3/iki_write/c/iki_write.h create mode 100644 level_3/iki_write/c/main.c create mode 100644 level_3/iki_write/c/private-iki_write.c create mode 100644 level_3/iki_write/c/private-iki_write.h create mode 100644 level_3/iki_write/data/build/defines create mode 100644 level_3/iki_write/data/build/dependencies create mode 100644 level_3/iki_write/data/build/settings diff --git a/build/level_0/settings b/build/level_0/settings index 565a1ac..fc78356 100644 --- a/build/level_0/settings +++ b/build/level_0/settings @@ -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 diff --git a/build/level_2/settings b/build/level_2/settings index 6055baa..1c5ce91 100644 --- a/build/level_2/settings +++ b/build/level_2/settings @@ -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 diff --git a/build/monolithic/settings b/build/monolithic/settings index 99a6d86..ffb50c0 100644 --- a/build/monolithic/settings +++ b/build/monolithic/settings @@ -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 diff --git a/build/scripts/bootstrap-example.sh b/build/scripts/bootstrap-example.sh index cf48c8b..e70a18c 100644 --- a/build/scripts/bootstrap-example.sh +++ b/build/scripts/bootstrap-example.sh @@ -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/ && diff --git a/level_0/f_iki/c/iki.c b/level_0/f_iki/c/iki.c index 40911f0..e227a18 100644 --- a/level_0/f_iki/c/iki.c +++ b/level_0/f_iki/c/iki.c @@ -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) { diff --git a/level_0/f_iki/c/iki.h b/level_0/f_iki/c/iki.h index 503277c..807aacb 100644 --- a/level_0/f_iki/c/iki.h +++ b/level_0/f_iki/c/iki.h @@ -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 index 0000000..d45ea1d --- /dev/null +++ b/level_0/f_iki/c/private-iki.c @@ -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 index 0000000..bba6738 --- /dev/null +++ b/level_0/f_iki/c/private-iki.h @@ -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 diff --git a/level_0/f_iki/data/build/settings b/level_0/f_iki/data/build/settings index 7e1f20a..dce71cb 100644 --- a/level_0/f_iki/data/build/settings +++ b/level_0/f_iki/data/build/settings @@ -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 index 0000000..6f4e88f --- /dev/null +++ b/level_2/fll_iki/c/iki.c @@ -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 index 0000000..82537ef --- /dev/null +++ b/level_2/fll_iki/c/iki.h @@ -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 +#include +#include + +// fll-0 includes +#include +#include +#include +#include +#include +#include + +// fll-1 includes +#include +#include + +#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 index 0000000..6e666f7 --- /dev/null +++ b/level_2/fll_iki/c/private-iki.c @@ -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 index 0000000..9d8939a --- /dev/null +++ b/level_2/fll_iki/c/private-iki.h @@ -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 index 0000000..c665317 --- /dev/null +++ b/level_2/fll_iki/data/build/defines @@ -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 index 0000000..60e504d --- /dev/null +++ b/level_2/fll_iki/data/build/dependencies @@ -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 index 0000000..9ac1c02 --- /dev/null +++ b/level_2/fll_iki/data/build/settings @@ -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 index 0000000..87cf4bf --- /dev/null +++ b/level_3/iki_write/c/iki_write.c @@ -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 index 0000000..becd244 --- /dev/null +++ b/level_3/iki_write/c/iki_write.h @@ -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 +#include +#include +#include + +// fll-0 includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// fll-1 includes +#include +#include +#include +#include +#include +#include + +// fll-2 includes +#include +#include +#include + +#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 index 0000000..1ef60bc --- /dev/null +++ b/level_3/iki_write/c/main.c @@ -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 index 0000000..7d5eea1 --- /dev/null +++ b/level_3/iki_write/c/private-iki_write.c @@ -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 index 0000000..d1fec29 --- /dev/null +++ b/level_3/iki_write/c/private-iki_write.h @@ -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 index 0000000..c665317 --- /dev/null +++ b/level_3/iki_write/data/build/defines @@ -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 index 0000000..7f74885 --- /dev/null +++ b/level_3/iki_write/data/build/dependencies @@ -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 index 0000000..e7f026e --- /dev/null +++ b/level_3/iki_write/data/build/settings @@ -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 -- 1.8.3.1