--- /dev/null
+#include <level_3/bit_dump.h>
+#include "private-bit_dump.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_bit_dump_print_help_
+ f_return_status bit_dump_print_help(const bit_dump_data data) {
+ fll_program_print_help_header(data.context, bit_dump_name_long, bit_dump_version);
+
+ fll_program_print_help_option(data.context, f_console_standard_short_help, f_console_standard_long_help, " Print this help message.");
+ fll_program_print_help_option(data.context, f_console_standard_short_light, f_console_standard_long_light, " Output using colors that show up better on light backgrounds");
+ fll_program_print_help_option(data.context, f_console_standard_short_dark, f_console_standard_long_dark, " Output using colors that show up better on dark backgrounds");
+ fll_program_print_help_option(data.context, f_console_standard_short_no_color, f_console_standard_long_no_color, " Do not output in color.");
+ fll_program_print_help_option(data.context, f_console_standard_short_version, f_console_standard_long_version, " Print only the version number.");
+
+ printf("%c", f_string_eol);
+
+ fll_program_print_help_option(data.context, bit_dump_short_binary, bit_dump_long_binary, " Display binary representation.");
+ fll_program_print_help_option(data.context, bit_dump_short_hex, bit_dump_long_hex, " Display hexadecimal representation.");
+
+ fll_program_print_help_usage(data.context, bit_dump_name, "filename(s)");
+
+ printf("When using the ");
+ fl_color_print(f_standard_output, data.context.notable, data.context.reset, "--%s", bit_dump_long_text);
+ printf(" option, some UTF-8 characters may be replaced by your instance and cause display alignment issues.");
+
+ printf("%c%c", f_string_eol, f_string_eol);
+
+ printf("Special UTF-8 characters and non-spacing UTF-8 characters may be replaced with a space (or a placeholder when the ");
+ fl_color_print(f_standard_output, data.context.notable, data.context.reset, "--%s", bit_dump_long_placeholder);
+ printf(" option is used).");
+
+ printf("%c%c", f_string_eol, f_string_eol);
+
+ return f_none;
+ }
+#endif // _di_bit_dump_print_help_
+
+#ifndef _di_bit_dump_main_
+ f_return_status bit_dump_main(const f_array_length argc, const f_string argv[], bit_dump_data *data) {
+ f_status status = fll_program_process_parameters(argc, argv, data->parameters, bit_dump_total_parameters, bit_dump_parameter_no_color, bit_dump_parameter_light, bit_dump_parameter_dark, &data->remaining, &data->context);
+
+ if (f_status_is_error(status)) {
+ bit_dump_delete_data(data);
+ return f_status_set_error(status);
+ }
+
+ if (data->parameters[bit_dump_parameter_binary].result == f_console_result_found) {
+ if (data->parameters[bit_dump_parameter_hexidecimal].result == f_console_result_none) {
+ if (data->parameters[bit_dump_parameter_octal].result == f_console_result_none || data->parameters[bit_dump_parameter_binary].location > data->parameters[bit_dump_parameter_octal].location) {
+ data->mode = bit_dump_mode_binary;
+ }
+ else if (data->parameters[bit_dump_parameter_binary].location == data->parameters[bit_dump_parameter_octal].location && data->parameters[bit_dump_parameter_binary].location_sub > data->parameters[bit_dump_parameter_octal].location_sub) {
+ data->mode = bit_dump_mode_binary;
+ }
+ else {
+ data->mode = bit_dump_mode_octal;
+ }
+ }
+ else {
+ if (data->parameters[bit_dump_parameter_octal].result == f_console_result_none) {
+ if (data->parameters[bit_dump_parameter_binary].location > data->parameters[bit_dump_parameter_hexidecimal].location) {
+ data->mode = bit_dump_mode_binary;
+ }
+ else if (data->parameters[bit_dump_parameter_binary].location == data->parameters[bit_dump_parameter_hexidecimal].location && data->parameters[bit_dump_parameter_binary].location_sub > data->parameters[bit_dump_parameter_hexidecimal].location_sub) {
+ data->mode = bit_dump_mode_binary;
+ }
+ else {
+ data->mode = bit_dump_mode_hexidecimal;
+ }
+ }
+ else if (data->parameters[bit_dump_parameter_binary].location > data->parameters[bit_dump_parameter_octal].location) {
+ if (data->parameters[bit_dump_parameter_binary].location > data->parameters[bit_dump_parameter_hexidecimal].location) {
+ data->mode = bit_dump_mode_binary;
+ }
+ else if (data->parameters[bit_dump_parameter_binary].location == data->parameters[bit_dump_parameter_hexidecimal].location && data->parameters[bit_dump_parameter_binary].location_sub > data->parameters[bit_dump_parameter_hexidecimal].location_sub) {
+ data->mode = bit_dump_mode_binary;
+ }
+ else {
+ data->mode = bit_dump_mode_hexidecimal;
+ }
+ }
+ else if (data->parameters[bit_dump_parameter_binary].location == data->parameters[bit_dump_parameter_octal].location && data->parameters[bit_dump_parameter_binary].location_sub > data->parameters[bit_dump_parameter_octal].location_sub) {
+ if (data->parameters[bit_dump_parameter_binary].location > data->parameters[bit_dump_parameter_hexidecimal].location) {
+ data->mode = bit_dump_mode_binary;
+ }
+ else if (data->parameters[bit_dump_parameter_binary].location == data->parameters[bit_dump_parameter_hexidecimal].location && data->parameters[bit_dump_parameter_binary].location_sub > data->parameters[bit_dump_parameter_hexidecimal].location_sub) {
+ data->mode = bit_dump_mode_binary;
+ }
+ else {
+ data->mode = bit_dump_mode_hexidecimal;
+ }
+ }
+ else if (data->parameters[bit_dump_parameter_hexidecimal].location > data->parameters[bit_dump_parameter_octal].location) {
+ data->mode = bit_dump_mode_hexidecimal;
+ }
+ else if (data->parameters[bit_dump_parameter_hexidecimal].location == data->parameters[bit_dump_parameter_octal].location && data->parameters[bit_dump_parameter_hexidecimal].location_sub > data->parameters[bit_dump_parameter_octal].location_sub) {
+ data->mode = bit_dump_mode_hexidecimal;
+ }
+ else {
+ data->mode = bit_dump_mode_octal;
+ }
+ }
+ }
+ else if (data->parameters[bit_dump_parameter_hexidecimal].result == f_console_result_found) {
+ if (data->parameters[bit_dump_parameter_octal].result == f_console_result_none || data->parameters[bit_dump_parameter_hexidecimal].location > data->parameters[bit_dump_parameter_octal].location) {
+ data->mode = bit_dump_mode_hexidecimal;
+ }
+ else if (data->parameters[bit_dump_parameter_hexidecimal].location == data->parameters[bit_dump_parameter_octal].location && data->parameters[bit_dump_parameter_hexidecimal].location_sub > data->parameters[bit_dump_parameter_octal].location_sub) {
+ data->mode = bit_dump_mode_hexidecimal;
+ }
+ else {
+ data->mode = bit_dump_mode_octal;
+ }
+ }
+ else if (data->parameters[bit_dump_parameter_octal].result == f_console_result_found) {
+ data->mode = bit_dump_mode_octal;
+ }
+
+ status = f_none;
+
+ // execute parameter results.
+ if (data->parameters[bit_dump_parameter_help].result == f_console_result_found) {
+ bit_dump_print_help(*data);
+ }
+ else if (data->parameters[bit_dump_parameter_version].result == f_console_result_found) {
+ fll_program_print_version(bit_dump_version);
+ }
+ else if (data->remaining.used > 0 || data->process_pipe) {
+ if (data->parameters[bit_dump_parameter_width].result == f_console_result_found) {
+ fl_color_print_line(f_standard_output, data->context.error, data->context.reset, "Width option was specified but no width was given.");
+
+ bit_dump_delete_data(data);
+ return f_status_set_error(status);
+ }
+ else if (data->parameters[bit_dump_parameter_width].result == f_console_result_additional) {
+ uint64_t number = atoll(argv[data->parameters[bit_dump_parameter_width].additional.array[0]]);
+ if (number < 1 || number >= 0xfb) {
+ fl_color_print_line(f_standard_output, data->context.error, data->context.reset, "Width option can only be a number between 0 and 251.");
+
+ bit_dump_delete_data(data);
+ return f_status_set_error(status);
+ }
+
+ data->width = (uint8_t) number;
+ }
+
+ if (data->parameters[bit_dump_parameter_first].result == f_console_result_found) {
+ fl_color_print_line(f_standard_output, data->context.error, data->context.reset, "First option was specified but no number was given.");
+
+ bit_dump_delete_data(data);
+ return f_status_set_error(status);
+ }
+ else if (data->parameters[bit_dump_parameter_first].result == f_console_result_additional) {
+ uint64_t number = atoll(argv[data->parameters[bit_dump_parameter_first].additional.array[0]]);
+ if (number < 1 || number >= 0xffffffffffffffff) {
+ fl_color_print_line(f_standard_output, data->context.error, data->context.reset, "First option can only be a number between 0 and 18446744073709551615.");
+
+ bit_dump_delete_data(data);
+ return f_status_set_error(status);
+ }
+
+ data->first = number;
+ }
+
+ if (data->parameters[bit_dump_parameter_last].result == f_console_result_found) {
+ fl_color_print_line(f_standard_output, data->context.error, data->context.reset, "Last option was specified but no number was given.");
+
+ bit_dump_delete_data(data);
+ return f_status_set_error(status);
+ }
+ else if (data->parameters[bit_dump_parameter_last].result == f_console_result_additional) {
+ uint64_t number = atoll(argv[data->parameters[bit_dump_parameter_last].additional.array[0]]);
+ if (number < 1 || number >= 0xffffffffffffffff) {
+ fl_color_print_line(f_standard_output, data->context.error, data->context.reset, "Last option can only be a number between 0 and 18446744073709551615.");
+
+ bit_dump_delete_data(data);
+ return f_status_set_error(status);
+ }
+
+ data->last = number;
+ }
+
+ if (data->first > data->last) {
+ fl_color_print(f_standard_output, data->context.error, data->context.reset, "First option (");
+ fl_color_print(f_standard_output, data->context.notable, data->context.reset, "%d", data->first);
+ fl_color_print(f_standard_output, data->context.error, data->context.reset, ") cannot be greater than Last option (");
+ fl_color_print(f_standard_output, data->context.notable, data->context.reset, "%d", data->last);
+ fl_color_print_line(f_standard_output, data->context.error, data->context.reset, ").");
+
+ bit_dump_delete_data(data);
+ return f_status_set_error(status);
+ }
+
+ if (data->process_pipe) {
+ // TODO: how should this be done?
+ }
+
+ if (data->remaining.used > 0) {
+ // pre-process remaining arguments to ensure that they all files exist before processing.
+ {
+ f_status missing_files = f_none;
+
+ for (f_array_length counter = 0; counter < data->remaining.used; counter++) {
+ status = f_file_exists(argv[data->remaining.array[counter]]);
+ if (status == f_false || f_status_is_error(status)) {
+ if (missing_files == f_none) {
+ missing_files = status;
+ }
+
+ bit_dump_print_file_error(data->context, status, "f_file_exists", argv[data->remaining.array[counter]]);
+ }
+ } // for
+
+ if (missing_files != f_none) {
+ status = f_status_set_error(missing_files);
+
+ bit_dump_delete_data(data);
+ return status;
+ }
+ }
+
+ for (f_array_length counter = 0; counter < data->remaining.used; counter++) {
+ f_file file = f_file_initialize;
+
+ status = f_file_open(&file, argv[data->remaining.array[counter]]);
+ if (f_status_is_error(status)) {
+ bit_dump_print_file_error(data->context, status, "f_file_open", argv[data->remaining.array[counter]]);
+ bit_dump_delete_data(data);
+ return status;
+ }
+
+ printf("%c", f_string_eol);
+ fl_color_print(f_standard_output, data->context.title, data->context.reset, "Byte Dump of: ");
+ fl_color_print_line(f_standard_output, data->context.notable, data->context.reset, "%s", argv[data->remaining.array[counter]]);
+
+ status = bit_dump_file(*data, argv[data->remaining.array[counter]], file);
+
+ f_file_close(&file);
+
+ if (f_status_is_error(status)) {
+ bit_dump_delete_data(data);
+ return status;
+ }
+ } // for
+ }
+ else {
+ status = f_false;
+ }
+ }
+ else {
+ fl_color_print_line(f_standard_error, data->context.error, data->context.reset, "ERROR: you failed to specify an error code.");
+ status = f_status_set_error(f_invalid_parameter);
+ }
+
+ bit_dump_delete_data(data);
+ return status;
+ }
+#endif // _di_bit_dump_main_
+
+#ifndef _di_bit_dump_delete_data_
+ f_return_status bit_dump_delete_data(bit_dump_data *data) {
+ f_status status = f_none;
+
+ for (f_string_length i = 0; i < bit_dump_total_parameters; i++) {
+ f_macro_string_lengths_delete(status, data->parameters[i].additional);
+ } // for
+
+ f_macro_string_lengths_delete(status, data->remaining);
+ fl_macro_color_context_delete(status, data->context);
+
+ return f_none;
+ }
+#endif // _di_bit_dump_delete_data_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 3
+ *
+ * Project: Bit Dump
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ *
+ * This is intendend to support Unicode 12.1.
+ *
+ * When using "text" mode, this program attempts to translate UTF-8 sequences such that certain codes don't cause printing problems.
+ * There may be cases where there are unknown codes that get printed and the invalid UTF-8 marker may be displayed not by this program but instead by the shell or some other program.
+ * This can potentially be seen with the program "less".
+ * The solution is to add the invalid character codes to this project so that this project can properly print the invalid UTF-8 marker and therefore properly display the information.
+ */
+#ifndef _bit_dump_h
+
+// libc includes
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+// fll-0 includes
+#include <level_0/console.h>
+#include <level_0/conversion.h>
+#include <level_0/pipe.h>
+#include <level_0/print.h>
+#include <level_0/status.h>
+#include <level_0/string.h>
+#include <level_0/type.h>
+#include <level_0/utf.h>
+
+// fll-1 includes
+#include <level_1/color.h>
+#include <level_1/console.h>
+#include <level_1/string.h>
+#include <level_1/utf.h>
+
+// fll-2 includes
+#include <level_2/program.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_bit_dump_version_
+ #define bit_dump_major_version "0"
+ #define bit_dump_minor_version "5"
+ #define bit_dump_micro_version "0"
+ #define bit_dump_version bit_dump_major_version "." bit_dump_minor_version "." bit_dump_micro_version
+#endif // _di_bit_dump_version_
+
+#ifndef _di_bit_dump_name_
+ #define bit_dump_name "bit_dump"
+ #define bit_dump_name_long "Bit Dump"
+#endif // _di_bit_dump_name_
+
+#ifndef _di_bit_dump_default_allocation_step_
+ // provide a UTF-8 friendly allocation step.
+ #define bit_dump_default_allocation_step 4
+#endif // _di_bit_dump_default_allocation_step_
+
+#ifndef _di_bit_dump_defines_
+ enum {
+ bit_dump_mode_hexidecimal,
+ bit_dump_mode_octal,
+ bit_dump_mode_binary,
+ bit_dump_mode_digit,
+ };
+
+ #define bit_dump_sequence_acknowledge "␆"
+ #define bit_dump_sequence_backspace "␈"
+ #define bit_dump_sequence_bell "␇"
+ #define bit_dump_sequence_cancel "␘"
+ #define bit_dump_sequence_carriage_return "␍"
+ #define bit_dump_sequence_data_link_escape "␐"
+ #define bit_dump_sequence_delete "␡"
+ #define bit_dump_sequence_device_control_1 "␑"
+ #define bit_dump_sequence_device_control_2 "␒"
+ #define bit_dump_sequence_device_control_3 "␓"
+ #define bit_dump_sequence_device_control_4 "␔"
+ #define bit_dump_sequence_end_of_enquiry "␅"
+ #define bit_dump_sequence_end_of_medium "␙"
+ #define bit_dump_sequence_end_of_text "␃"
+ #define bit_dump_sequence_end_of_transmission "␄"
+ #define bit_dump_sequence_end_of_transmission_block "␗"
+ #define bit_dump_sequence_escape "␛"
+ #define bit_dump_sequence_file_separator "␜"
+ #define bit_dump_sequence_form_feed "␌"
+ #define bit_dump_sequence_group_separator "␝"
+ #define bit_dump_sequence_line_feed "␊"
+ #define bit_dump_sequence_negative_acknowledge "␕"
+ #define bit_dump_sequence_new_line ""
+ #define bit_dump_sequence_null "␀"
+ #define bit_dump_sequence_record_separator "␞"
+ #define bit_dump_sequence_shift_in "␏"
+ #define bit_dump_sequence_shift_out "␎"
+ #define bit_dump_sequence_space "␠"
+ #define bit_dump_sequence_start_of_header "␁"
+ #define bit_dump_sequence_start_of_text "␂"
+ #define bit_dump_sequence_substitute "␚"
+ #define bit_dump_sequence_synchronous_idle "␖"
+ #define bit_dump_sequence_tab "␉"
+ #define bit_dump_sequence_tab_vertical "␋"
+ #define bit_dump_sequence_unit_separator "␟"
+ #define bit_dump_sequence_utf_bom "␂"
+
+ #define bit_dump_character_wall "|"
+ #define bit_dump_character_placeholder "␣" // other likely choices: (substitute form 1: '␚', substitute form 2: '␦').
+ #define bit_dump_character_incomplete "�"
+ #define bit_dump_character_unused "�"
+
+ #define bit_dump_short_binary "b"
+ #define bit_dump_short_hex "x"
+ #define bit_dump_short_octal "o"
+
+ #define bit_dump_short_first "f"
+ #define bit_dump_short_last "l"
+ #define bit_dump_short_text "t"
+ #define bit_dump_short_width "w"
+ #define bit_dump_short_placeholder "p"
+
+ #define bit_dump_long_binary "binary"
+ #define bit_dump_long_hex "hex"
+ #define bit_dump_long_octal "octal"
+
+ #define bit_dump_long_first "first" // first offset byte size.
+ #define bit_dump_long_last "last" // last offset byte size.
+ #define bit_dump_long_width "width" // number of characters to display per row.
+
+ #define bit_dump_long_text "text" // display text
+ #define bit_dump_long_placeholder "placeholder" // display (colored) placeholders to signify codes that are UTF-8 fragments.
+
+ enum {
+ bit_dump_parameter_help,
+ bit_dump_parameter_light,
+ bit_dump_parameter_dark,
+ bit_dump_parameter_no_color,
+ bit_dump_parameter_version,
+
+ bit_dump_parameter_binary,
+ bit_dump_parameter_hexidecimal,
+ bit_dump_parameter_octal,
+ // @todo: add digit print support bit_dump_parameter_digit,
+
+ bit_dump_parameter_first,
+ bit_dump_parameter_last,
+ bit_dump_parameter_width,
+
+ bit_dump_parameter_text,
+ bit_dump_parameter_placeholder,
+ };
+
+ #define bit_dump_console_parameter_initialize \
+ { \
+ f_console_parameter_initialize(f_console_standard_short_help, f_console_standard_long_help, 0, 0, f_console_type_normal), \
+ f_console_parameter_initialize(f_console_standard_short_light, f_console_standard_long_light, 0, 0, f_console_type_inverse), \
+ f_console_parameter_initialize(f_console_standard_short_dark, f_console_standard_long_dark, 0, 0, f_console_type_inverse), \
+ f_console_parameter_initialize(f_console_standard_short_no_color, f_console_standard_long_no_color, 0, 0, f_console_type_inverse), \
+ f_console_parameter_initialize(f_console_standard_short_version, f_console_standard_long_version, 0, 0, f_console_type_inverse), \
+ f_console_parameter_initialize(bit_dump_short_binary, bit_dump_long_binary, 0, 0, f_console_type_normal), \
+ f_console_parameter_initialize(bit_dump_short_hex, bit_dump_long_hex, 0, 0, f_console_type_normal), \
+ f_console_parameter_initialize(bit_dump_short_octal, bit_dump_long_octal, 0, 0, f_console_type_normal), \
+ f_console_parameter_initialize(bit_dump_short_first, bit_dump_long_first, 0, 1, f_console_type_normal), \
+ f_console_parameter_initialize(bit_dump_short_last, bit_dump_long_last, 0, 1, f_console_type_normal), \
+ f_console_parameter_initialize(bit_dump_short_width, bit_dump_long_width, 0, 1, f_console_type_normal), \
+ f_console_parameter_initialize(bit_dump_short_text, bit_dump_long_text, 0, 0, f_console_type_normal), \
+ f_console_parameter_initialize(bit_dump_short_placeholder, bit_dump_long_placeholder, 0, 0, f_console_type_normal), \
+ }
+
+ #define bit_dump_total_parameters 13
+#endif // _di_bit_dump_defines_
+
+#ifndef _di_bit_dump_data_
+ typedef struct {
+ f_console_parameter parameters[bit_dump_total_parameters];
+
+ f_string_lengths remaining;
+ f_bool process_pipe;
+
+ uint64_t first;
+ uint64_t last;
+ uint8_t width;
+ uint8_t mode;
+
+ fl_color_context context;
+ } bit_dump_data;
+
+ #define bit_dump_data_initialize \
+ { \
+ bit_dump_console_parameter_initialize, \
+ f_string_lengths_initialize, \
+ f_false, \
+ 0, \
+ 0, \
+ 8, \
+ bit_dump_mode_hexidecimal, \
+ fl_color_context_initialize, \
+ }
+#endif // _di_bit_dump_data_
+
+/**
+ * Print help to standard output.
+ *
+ * @param data
+ * The program data.
+ *
+ * @return
+ * f_none on success.
+ */
+#ifndef _di_bit_dump_print_help_
+ extern f_return_status bit_dump_print_help(const bit_dump_data data);
+#endif // _di_bit_dump_print_help_
+
+/**
+ * Execute main program.
+ *
+ * Be sure to call bit_dump_delete_data() after executing this.
+ *
+ * @param argc
+ * The number of parameters passed to the process.
+ * @param argv
+ * 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 bit_dump_delete_data()
+ */
+#ifndef _di_bit_dump_main_
+ extern f_return_status bit_dump_main(const f_array_length argc, const f_string argv[], bit_dump_data *data);
+#endif // _di_bit_dump_main_
+
+/**
+ * Deallocate data.
+ *
+ * Be sure to call this after executing bit_dump_main().
+ *
+ * @param data
+ * The program data.
+ *
+ * @return
+ * f_none on success.
+ * Status codes (with error bit) are returned on any problem.
+ *
+ * @see bit_dump_main()
+ */
+#ifndef _di_bit_dump_delete_data_
+ extern f_return_status bit_dump_delete_data(bit_dump_data *data);
+#endif // _di_bit_dump_delete_data_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _bit_dump_h
--- /dev/null
+/**
+ * Private source file for firewall.c.
+ */
+#include <level_3/bit_dump.h>
+#include "private-bit_dump.h"
+
+#ifndef _di_bit_dump_file_
+ f_return_status bit_dump_file(const bit_dump_data data, const f_string file_name, f_file file) {
+ f_status status = f_none;
+
+ uint64_t position = data.first;
+ uint64_t row = 0;
+ uint8_t size = 0;
+ uint8_t byte = 0;
+ uint8_t column = 0;
+
+ int8_t width_utf = -1;
+ int8_t width_current = 0;
+ int8_t width_count = 0;
+
+ // UTF-8 Characters bytes may overflow beyond the data.width.
+ // These overflowed bytes should still have placeholders printed in the next text-mode print.
+ uint8_t previous_bytes = 0;
+ uint8_t previous_invalid = 0;
+
+ f_bool character_reset = 0;
+ f_bool found_invalid_utf = f_false;
+
+ // Store the current character data until it can be printed.
+ f_utf_string_dynamic characters = f_utf_string_dynamic_initialize;
+ f_utf_character character_array[data.width];
+ f_utf_string_length character_current = 0;
+
+ memset(&character_array, 0, sizeof(f_utf_character) * data.width);
+ characters.string = character_array;
+ characters.used = 0;
+ characters.size = data.width;
+
+ // Record when a character is invalid.
+ uint8_t invalid[data.width];
+ memset(&invalid, 0, sizeof(uint8_t) * data.width);
+
+ fseek(file.address, data.first, SEEK_SET);
+
+ while ((size = read(file.id, &byte, 1)) > 0) {
+ // Storing the next character is designated by width_utf == -1.
+ if (width_utf == -1) {
+ width_utf = f_macro_utf_byte_width_is(byte);
+ width_count = 0;
+
+ // The character is reset, the characters.used is to be reset.
+ if (character_reset) {
+ characters.used = 0;
+ character_reset = f_false;
+ memset(&invalid, 0, sizeof(uint8_t) * data.width);
+ }
+
+ character_current = characters.used;
+ characters.used++;
+
+ invalid[character_current] = 0;
+ }
+
+ // When width_count == 0, then this is that start of a new character sequence.
+ if (width_count == 0) {
+ characters.string[character_current] = f_macro_utf_character_from_char_1(byte);
+ width_count = 1;
+
+ // The first character in a UTF-8 sequence cannot have a width of 1.
+ if (width_utf == 1) {
+ found_invalid_utf = f_true;
+ invalid[character_current] = 1;
+ }
+ // UTF-8 characters with width of 4 cannot have any characters of 0x8f as the first byte.
+ else if (width_utf == 4 && byte == 0x8f) {
+ found_invalid_utf = f_true;
+ invalid[character_current] = width_utf;
+ }
+ // These are not defined in Unicode, and so are considered invalid in UTF-8, regardless of their width_utf.
+ else if (byte >= 0xf5) {
+ found_invalid_utf = f_true;
+ invalid[character_current] = width_utf;
+ }
+ // Sequences that start with 0xc1 are invalid because UTF-8 does not support overlong ASCII.
+ else if (byte == 0xc1) {
+ found_invalid_utf = f_true;
+ invalid[character_current] = width_utf;
+ }
+ // Process the UTF-8 character.
+ else if (width_utf > 1) {
+ position++;
+
+ if (data.last > 0 && position > data.last) break;
+
+ continue;
+ }
+ }
+ // Process a UTF-8 character fragment.
+ else if (width_count < width_utf) {
+ width_current = f_macro_utf_byte_width_is(byte);
+
+ if (width_count == 1) {
+ characters.string[character_current] |= f_macro_utf_character_from_char_2(byte);
+ }
+ else if (width_count == 2) {
+ characters.string[character_current] |= f_macro_utf_character_from_char_3(byte);
+ }
+ else if (width_count == 3) {
+ characters.string[character_current] |= f_macro_utf_character_from_char_4(byte);
+ }
+
+ width_count++;
+
+ // UTF-8 character fragments must have a width of 1 (and ASCII characters can only be the first character in a sequence).
+ if (width_current == 1) {
+ // Grab the next UTF-8 character fragment if the entire sequence is not collected yet.
+ if (width_count < width_utf) {
+ position++;
+
+ if (data.last > 0 && position > data.last) break;
+
+ continue;
+ }
+ }
+ else {
+ found_invalid_utf = f_true;
+ invalid[character_current] = width_utf;
+ }
+ }
+
+ // At this point: an ASCII character is collected, the entire UTF-8 character sequence is collected, or an invalid UTF-8 was processed.
+
+ // Handle special case invalid situations, 0xc0 and 0xc1 are used for two-byte encoding of a 7-bit ASCII but are considered invalid by UTF-8.
+ // Does not include 0xc0 0x80 because this is considered a overlong NULL in UTF-8, which is a valid NULL.
+ if (width_utf == 2 && characters.string[character_current] > 0xc0800000 && characters.string[character_current] <= 0xc0ff0000) {
+ found_invalid_utf = f_true;
+ invalid[character_current] = width_utf;
+ }
+ // The unicode codes U+D800 to U+DFFF are for "UTF-16 surrogate halves" which are not supported in UTF-8.
+ else if (width_utf == 3 && characters.string[character_current] > 0xefbfb000 && characters.string[character_current] <= 0xc0ff0000) {
+ found_invalid_utf = f_true;
+ invalid[character_current] = width_utf;
+ }
+
+ if (bit_dump_print_character_fragment(data, characters, invalid, width_utf, 1, &previous_bytes, &previous_invalid, &column, &row)) {
+ character_reset = f_true;
+ }
+
+ if (width_utf > 1) {
+ if (bit_dump_print_character_fragment(data, characters, invalid, width_utf, 2, &previous_bytes, &previous_invalid, &column, &row) == f_true) {
+ character_reset = f_true;
+ }
+
+ if (width_utf > 2) {
+ if (bit_dump_print_character_fragment(data, characters, invalid, width_utf, 3, &previous_bytes, &previous_invalid, &column, &row)) {
+ character_reset = f_true;
+ }
+
+ if (width_utf > 3) {
+ if (bit_dump_print_character_fragment(data, characters, invalid, width_utf, 4, &previous_bytes, &previous_invalid, &column, &row)) {
+ character_reset = f_true;
+ }
+ }
+ }
+ }
+
+ width_utf = -1;
+ position++;
+
+ if (data.last > 0 && position > data.last) break;
+ } // while
+
+ // Print placeholders to fill out the remaining line and then optionally print the text block.
+ if (column > 0 && column < data.width) {
+ previous_bytes = 0;
+ previous_invalid = 0;
+
+ while (column < data.width) {
+ if (data.mode == bit_dump_mode_hexidecimal) {
+ printf(" ");
+ }
+ else if (data.mode == bit_dump_mode_octal) {
+ printf(" ");
+ }
+ else if (data.mode == bit_dump_mode_binary) {
+ printf(" ");
+ }
+ else if (data.mode == bit_dump_mode_digit) {
+ // @todo
+ }
+
+ column++;
+
+ if (column < data.width) {
+ if (data.mode == bit_dump_mode_hexidecimal && column % 8 == 0) {
+ printf(" ");
+ }
+ else if (data.mode == bit_dump_mode_octal && column % 6 == 0) {
+ printf(" ");
+ }
+ else if (data.mode == bit_dump_mode_binary && column % 4 == 0) {
+ printf(" ");
+ }
+ else if (data.mode == bit_dump_mode_digit && column % 4 == 0) {
+ printf(" ");
+ }
+ }
+ } // while
+
+ if (data.parameters[bit_dump_parameter_text].result == f_console_result_found) {
+ bit_dump_print_text(data, characters, invalid, &previous_bytes, &previous_invalid);
+ }
+ else {
+ printf("%c", f_string_eol);
+ }
+ }
+
+ printf("%c", f_string_eol);
+
+ // make sure to flush standard out to help prevent standard error from causing poblems.
+ fflush(f_standard_output);
+
+ if (found_invalid_utf) {
+ fl_color_print(f_standard_error, data.context.error, data.context.reset, "Invalid UTF-8 codes were detected for file '");
+ fl_color_print(f_standard_error, data.context.notable, data.context.reset, "%s", file_name);
+ fl_color_print_line(f_standard_error, data.context.error, data.context.reset, "'.");
+ printf("%c", f_string_eol);
+ }
+
+ if (size < 0) {
+ // @todo: determine what the error from read() is and display it.
+ fl_color_print(f_standard_error, data.context.error, data.context.reset, "ERROR: read() failed for '");
+ fl_color_print(f_standard_error, data.context.notable, data.context.reset, "%s", file_name);
+ fl_color_print_line(f_standard_error, data.context.error, data.context.reset, "'.");
+ printf("%c", f_string_eol);
+ status = f_status_set_error(f_failure);
+ }
+
+ fflush(f_standard_error);
+
+ return status;
+ }
+#endif // _di_bit_dump_file_
+
+#ifndef _di_bit_dump_print_character_fragment_
+ f_bool bit_dump_print_character_fragment(const bit_dump_data data, const f_utf_string_dynamic characters, const uint8_t invalid[], const int8_t width_utf, const int8_t byte_current, uint8_t *previous_bytes, uint8_t *previous_invalid, uint8_t *column, uint64_t *row) {
+ uint8_t byte = 0;
+
+ f_bool reset = f_false;
+
+ f_utf_string_length character_current = characters.used - 1;
+
+ if (byte_current == 1) {
+ byte = f_macro_utf_character_to_char_1(characters.string[character_current]);
+ }
+ else if (byte_current == 2) {
+ byte = f_macro_utf_character_to_char_2(characters.string[character_current]);
+ }
+ else if (byte_current == 3) {
+ byte = f_macro_utf_character_to_char_3(characters.string[character_current]);
+ }
+ else if (byte_current == 4) {
+ byte = f_macro_utf_character_to_char_4(characters.string[character_current]);
+ }
+
+ if (*column == 0) {
+ fl_color_print(f_standard_output, data.context.notable, data.context.reset, "%016X ", (uint64_t) *row);
+ }
+
+ if (data.mode == bit_dump_mode_hexidecimal) {
+ if (invalid[character_current]) {
+ fl_color_print(f_standard_output, data.context.error, data.context.reset, " %02x", (uint8_t) byte);
+ }
+ else {
+ printf(" %02x", (uint8_t) byte);
+ }
+ }
+ else if (data.mode == bit_dump_mode_octal) {
+ if (invalid[character_current]) {
+ fl_color_print(f_standard_output, data.context.error, data.context.reset, " %03o", (uint8_t) byte);
+ }
+ else {
+ printf(" %03o", (uint8_t) byte);
+ }
+ }
+ else if (data.mode == bit_dump_mode_binary) {
+ char binary_string[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ binary_string[0] = ((byte >> 7) & 0x01) ? '1' : '0';
+ binary_string[1] = ((byte >> 6) & 0x01) ? '1' : '0';
+ binary_string[2] = ((byte >> 5) & 0x01) ? '1' : '0';
+ binary_string[3] = ((byte >> 4) & 0x01) ? '1' : '0';
+ binary_string[4] = ((byte >> 3) & 0x01) ? '1' : '0';
+ binary_string[5] = ((byte >> 2) & 0x01) ? '1' : '0';
+ binary_string[6] = ((byte >> 1) & 0x01) ? '1' : '0';
+ binary_string[7] = (byte & 0x01) ? '1' : '0';
+
+ if (invalid[character_current]) {
+ fl_color_print(f_standard_output, data.context.error, data.context.reset, " %s", binary_string);
+ }
+ else {
+ printf(" %s", binary_string);
+ }
+ }
+ else if (data.mode == bit_dump_mode_digit) {
+ if (invalid[character_current]) {
+ fl_color_print(f_standard_output, data.context.error, data.context.reset, " %02d", (uint8_t) byte);
+ }
+ else {
+ printf(" %02d", (uint8_t) byte);
+ }
+ }
+
+ (*column)++;
+
+ if (*column == data.width) {
+ uint8_t bytes = 0;
+
+ if (byte_current < width_utf) {
+ bytes = width_utf - byte_current;
+ }
+
+ reset = f_true;
+
+ if (data.parameters[bit_dump_parameter_text].result == f_console_result_found) {
+ bit_dump_print_text(data, characters, invalid, previous_bytes, previous_invalid);
+ }
+ else {
+ printf("%c", f_string_eol);
+ }
+
+ *column = 0;
+ (*row)++;
+
+ if (bytes == 0) {
+ *previous_bytes = 0;
+ *previous_invalid = 0;
+ }
+ else {
+ *previous_bytes = bytes;
+ *previous_invalid = invalid[character_current];
+ }
+ }
+ else if (data.mode == bit_dump_mode_hexidecimal && *column % 8 == 0) {
+ printf(" ");
+ }
+ else if (data.mode == bit_dump_mode_octal && *column % 6 == 0) {
+ printf(" ");
+ }
+ else if (data.mode == bit_dump_mode_binary && *column % 4 == 0) {
+ printf(" ");
+ }
+ else if (data.mode == bit_dump_mode_digit && *column % 4 == 0) {
+ printf(" ");
+ }
+
+ return reset;
+ }
+#endif // _di_bit_dump_print_character_fragment_
+
+#ifndef _di_bit_dump_print_text_
+ void bit_dump_print_text(const bit_dump_data data, const f_utf_string_dynamic characters, const uint8_t invalid[], uint8_t *previous_bytes, uint8_t *previous_invalid) {
+ uint8_t j = 0;
+ uint8_t output = 0;
+ uint8_t width_utf = 0;
+
+ fl_color_print(f_standard_output, data.context.notable, data.context.reset, " %s ", bit_dump_character_wall);
+
+ // Print placeholders for the remaining fragments of UTF-8 characters printed on previous lines.
+ {
+ uint8_t bytes_overflow = 0;
+
+ if ((*previous_bytes - 1) > data.width) {
+ bytes_overflow = (*previous_bytes) - 1 - data.width;
+ }
+
+ if (*previous_bytes > 0) {
+ if (data.parameters[bit_dump_parameter_placeholder].result == f_console_result_found) {
+ for (; j < *previous_bytes && j < data.width; j++) {
+ if (*previous_invalid) {
+ fl_color_print(f_standard_output, data.context.error, data.context.reset, "%s", bit_dump_character_placeholder);
+ }
+ else {
+ fl_color_print(f_standard_output, data.context.warning, data.context.reset, "%s", bit_dump_character_placeholder);
+ }
+ } // for
+ }
+ else {
+ for (; j < *previous_bytes && j < data.width; j++) {
+ printf(" ");
+ } // for
+ }
+ }
+
+ if (bytes_overflow > 0) {
+ *previous_bytes = bytes_overflow;
+ }
+ else {
+ *previous_bytes = 0;
+ *previous_invalid = 0;
+ }
+ }
+
+ for (uint8_t i = 0; i < characters.used && j < data.width; i++, j++) {
+ output = f_macro_utf_character_to_char_1(characters.string[i]);
+ width_utf = f_macro_utf_byte_width_is(output);
+
+ if (invalid[i]) {
+ fl_color_print(f_standard_output, data.context.error, data.context.reset, "%s", bit_dump_character_incomplete);
+ }
+ else if (output == 0) {
+ printf("%s", bit_dump_sequence_null);
+ }
+ else if (output == 1) {
+ printf("%s", bit_dump_sequence_start_of_header);
+ }
+ else if (output == 2) {
+ printf("%s", bit_dump_sequence_start_of_text);
+ }
+ else if (output == 3) {
+ printf("%s", bit_dump_sequence_end_of_text);
+ }
+ else if (output == 4) {
+ printf("%s", bit_dump_sequence_end_of_transmission);
+ }
+ else if (output == 5) {
+ printf("%s", bit_dump_sequence_end_of_enquiry);
+ }
+ else if (output == 6) {
+ printf("%s", bit_dump_sequence_acknowledge);
+ }
+ else if (output == 7) {
+ printf("%s", bit_dump_sequence_bell);
+ }
+ else if (output == 8) {
+ printf("%s", bit_dump_sequence_backspace);
+ }
+ else if (output == 9) {
+ printf("%s", bit_dump_sequence_tab);
+ }
+ else if (output == 10) {
+ printf("%s", bit_dump_sequence_new_line);
+ }
+ else if (output == 11) {
+ printf("%s", bit_dump_sequence_tab_vertical);
+ }
+ else if (output == 12) {
+ printf("%s", bit_dump_sequence_form_feed);
+ }
+ else if (output == 13) {
+ printf("%s", bit_dump_sequence_carriage_return);
+ }
+ else if (output == 14) {
+ printf("%s", bit_dump_sequence_shift_out);
+ }
+ else if (output == 15) {
+ printf("%s", bit_dump_sequence_shift_in);
+ }
+ else if (output == 16) {
+ printf("%s", bit_dump_sequence_data_link_escape);
+ }
+ else if (output == 17) {
+ printf("%s", bit_dump_sequence_device_control_1);
+ }
+ else if (output == 18) {
+ printf("%s", bit_dump_sequence_device_control_2);
+ }
+ else if (output == 19) {
+ printf("%s", bit_dump_sequence_device_control_3);
+ }
+ else if (output == 20) {
+ printf("%s", bit_dump_sequence_device_control_4);
+ }
+ else if (output == 21) {
+ printf("%s", bit_dump_sequence_negative_acknowledge);
+ }
+ else if (output == 22) {
+ printf("%s", bit_dump_sequence_synchronous_idle);
+ }
+ else if (output == 23) {
+ printf("%s", bit_dump_sequence_end_of_transmission_block);
+ }
+ else if (output == 24) {
+ printf("%s", bit_dump_sequence_cancel);
+ }
+ else if (output == 25) {
+ printf("%s", bit_dump_sequence_end_of_medium);
+ }
+ else if (output == 26) {
+ printf("%s", bit_dump_sequence_substitute);
+ }
+ else if (output == 27) {
+ printf("%s", bit_dump_sequence_escape);
+ }
+ else if (output == 28) {
+ printf("%s", bit_dump_sequence_file_separator);
+ }
+ else if (output == 29) {
+ printf("%s", bit_dump_sequence_group_separator);
+ }
+ else if (output == 30) {
+ printf("%s", bit_dump_sequence_record_separator);
+ }
+ else if (output == 31) {
+ printf("%s", bit_dump_sequence_unit_separator);
+ }
+ else if (output == 32) {
+ printf("%s", bit_dump_sequence_space);
+ }
+ else if (output == 127) {
+ printf("%s", bit_dump_sequence_delete);
+ }
+ else if (f_utf_is_whitespace_character(characters.string[i]) == f_true) {
+ printf("%s", bit_dump_sequence_space);
+ }
+ else if (width_utf == 2 && characters.string[i] == 0xc0800000) {
+ // This is an "Overlong Null" and is a valid NULL character.
+ printf("%s", bit_dump_sequence_null);
+ }
+ else if (width_utf == 2 && characters.string[i] >= 0xcc800000 && characters.string[i] <= 0xcdaf0000) {
+ // Combining characters should not be combined here, instead display a space.
+ printf(" ");
+ }
+ else if (width_utf == 3 && characters.string[i] >= 0xe1aab000 && characters.string[i] <= 0xe1abbf00) {
+ // Combining characters should not be combined here, instead display a space.
+ printf(" ");
+ }
+ else if (width_utf == 3 && characters.string[i] >= 0xe1b78000 && characters.string[i] <= 0xe1b7bf00) {
+ // Combining characters should not be combined here, instead display a space.
+ printf(" ");
+ }
+ else if (width_utf == 3 && characters.string[i] >= 0xe2839000 && characters.string[i] <= 0xe283bf00) {
+ // Combining characters should not be combined here, instead display a space.
+ printf(" ");
+ }
+ else if (width_utf == 2 && characters.string[i] >= 0xd8900000 && characters.string[i] <= 0xd89a0000) {
+ // Combining characters should not be combined here, instead display a space.
+ printf(" ");
+ }
+ else if (width_utf == 2 && characters.string[i] >= 0xc2800000 && characters.string[i] <= 0xc29f0000) {
+ // Use space to represent unprintable Latin-1 supplement control codes.
+ // 0xc2a00000 happens to be the non-breaking space character and is explicitly handled above.
+ printf(" ");
+ }
+ else if (width_utf == 3 && characters.string[i] >= 0xefbfb000 && characters.string[i] <= 0xefbfbc00) {
+ // Use space to represent Specials codes.
+ // 0xefbfbd00 is excluded because it is printable (and is the "Replacement Character" code).
+ printf(" ");
+ }
+ else if (width_utf == 3 && characters.string[i] >= 0xe290a700 && characters.string[i] <= 0xe290bf00) {
+ // Use space to represent Control Pictues codes that are not currently defined but are reserved.
+ printf(" ");
+ }
+ else if (width_utf == 3 && characters.string[i] >= 0xeda08000 && characters.string[i] <= 0xedadbf00) {
+ // Use space to represent High Surrogates codes.
+ printf(" ");
+ }
+ else if (width_utf == 3 && characters.string[i] >= 0xedae8000 && characters.string[i] <= 0xedafbf00) {
+ // Use space to represent High Private Use Surrogates codes.
+ printf(" ");
+ }
+ else if (width_utf == 3 && characters.string[i] >= 0xedb08000 && characters.string[i] <= 0xedbfbf00) {
+ // Use space to represent Low Surrogates codes.
+ printf(" ");
+ }
+ else if (width_utf == 3 && characters.string[i] >= 0xee808000 && characters.string[i] <= 0xefa3bf00) {
+ // Use space to represent Private Use Area codes.
+ printf(" ");
+ }
+ else if (width_utf == 4 && characters.string[i] >= 0xf09c80a0 && characters.string[i] <= 0xf09c80bd) {
+ // Use space to represent Vaiation Selectors Supplement codes.
+ printf(" ");
+ }
+ else if (width_utf == 4 && characters.string[i] >= 0xf09e8080 && characters.string[i] <= 0xf09fbfbf) {
+ // Use space to represent Supplemental Private Use Area-A codes.
+ printf(" ");
+ }
+ else if (width_utf == 4 && characters.string[i] >= 0xf0a08080 && characters.string[i] <= 0xf0a1bfbf) {
+ // Use space to represent Supplemental Private Use Area-B codes.
+ printf(" ");
+ }
+ else if (characters.string[i] == f_utf_character_mask_bom) {
+ fl_color_print(f_standard_output, data.context.warning, data.context.reset, "%s", bit_dump_sequence_utf_bom);
+ }
+ else if (width_utf == 1) {
+ // print invalid placeholder for invalid UTF-8 widths.
+ if (invalid[i]) {
+ fl_color_print(f_standard_output, data.context.error, data.context.reset, "%s", bit_dump_character_incomplete);
+ }
+ else {
+ fl_color_print(f_standard_output, data.context.warning, data.context.reset, "%s", bit_dump_character_incomplete);
+ }
+ }
+ else if (width_utf > 0) {
+ printf("%c", (uint8_t) output);
+
+ if (width_utf > 1) {
+ output = f_macro_utf_character_to_char_2(characters.string[i]);
+ printf("%c", (uint8_t) output);
+
+ if (width_utf > 2) {
+ output = f_macro_utf_character_to_char_3(characters.string[i]);
+ printf("%c", (uint8_t) output);
+
+ if (width_utf > 3) {
+ output = f_macro_utf_character_to_char_4(characters.string[i]);
+ printf("%c", (uint8_t) output);
+ }
+ }
+ }
+ }
+ else {
+ printf("%c", output);
+ }
+
+ // When using UTF-8 characters, the character columns will not line up, so print placeholders to simulate the bytes that are not printed, if necessary for alignment.
+ if (width_utf > 1 && j + 1 < data.width) {
+ if (data.parameters[bit_dump_parameter_placeholder].result == f_console_result_found) {
+ if (invalid[i]) {
+ fl_color_print(f_standard_output, data.context.error, data.context.reset, "%s", bit_dump_character_placeholder);
+ }
+ else {
+ fl_color_print(f_standard_output, data.context.warning, data.context.reset, "%s", bit_dump_character_placeholder);
+ }
+ }
+ else {
+ printf(" ");
+ }
+
+ j++;
+
+ if (width_utf > 2 && j + 1 < data.width) {
+ if (data.parameters[bit_dump_parameter_placeholder].result == f_console_result_found) {
+ if (invalid[i]) {
+ fl_color_print(f_standard_output, data.context.error, data.context.reset, "%s", bit_dump_character_placeholder);
+ }
+ else {
+ fl_color_print(f_standard_output, data.context.warning, data.context.reset, "%s", bit_dump_character_placeholder);
+ }
+ }
+ else {
+ printf(" ");
+ }
+
+ j++;
+
+ if (width_utf > 3 && j + 1 < data.width) {
+ if (data.parameters[bit_dump_parameter_placeholder].result == f_console_result_found) {
+ if (invalid[i]) {
+ fl_color_print(f_standard_output, data.context.error, data.context.reset, "%s", bit_dump_character_placeholder);
+ }
+ else {
+ fl_color_print(f_standard_output, data.context.warning, data.context.reset, "%s", bit_dump_character_placeholder);
+ }
+ }
+ else {
+ printf(" ");
+ }
+
+ j++;
+ }
+ }
+ }
+ } // for
+
+ // Print placeholder for the remaining parts of the line.
+ if (data.parameters[bit_dump_parameter_placeholder].result == f_console_result_found) {
+ for (; j < data.width; j++) {
+ if (invalid[j]) {
+ fl_color_print(f_standard_output, data.context.error, data.context.reset, "%s", bit_dump_character_placeholder);
+ }
+ else {
+ fl_color_print(f_standard_output, data.context.warning, data.context.reset, "%s", bit_dump_character_placeholder);
+ }
+ } // for
+ }
+ else {
+ for (; j < data.width; j++) {
+ printf(" ");
+ } // for
+ }
+
+ fl_color_print(f_standard_output, data.context.notable, data.context.reset, " |");
+ printf("%c", f_string_eol);
+ }
+#endif // _di_bit_dump_file_
+
+#ifndef _di_bit_dump_print_file_error_
+ void bit_dump_print_file_error(const fl_color_context context, const f_status status, const f_string function, const f_string file_name) {
+ f_status error = f_status_set_fine(status);
+
+ if (error == f_false) {
+ fl_color_print(f_standard_error, context.error, context.reset, "ERROR: failed to find file '");
+ fl_color_print(f_standard_error, context.notable, context.reset, "%s", file_name);
+ fl_color_print_line(f_standard_error, context.error, context.reset, "'.");
+ return;
+ }
+
+ if (error == f_invalid_parameter) {
+ fl_color_print(f_standard_error, context.error, context.reset, "INTERNAL ERROR: Invalid parameter when calling ", function, file_name);
+ fl_color_print(f_standard_error, context.notable, context.reset, "%s", function);
+ fl_color_print(f_standard_error, context.error, context.reset, "() for the file '");
+ fl_color_print(f_standard_error, context.notable, context.reset, "%s", file_name);
+ fl_color_print_line(f_standard_error, context.error, context.reset, "'.");
+ return;
+ }
+
+ if (error == f_invalid_name) {
+ fl_color_print(f_standard_error, context.error, context.reset, "ERROR: Invalid filename '");
+ fl_color_print(f_standard_error, context.notable, context.reset, "%s", file_name);
+ fl_color_print_line(f_standard_error, context.error, context.reset, "'.");
+ return;
+ }
+
+ if (error == f_out_of_memory) {
+ fl_color_print(f_standard_error, context.error, context.reset, "CRITICAL ERROR: unable to allocate memory, while trying to access file '");
+ fl_color_print(f_standard_error, context.notable, context.reset, "%s", file_name);
+ fl_color_print_line(f_standard_error, context.error, context.reset, "'.");
+ return;
+ }
+
+ if (error == f_overflow) {
+ fl_color_print(f_standard_error, context.error, context.reset, "ERROR: Overflow while trying to access file '");
+ fl_color_print(f_standard_error, context.notable, context.reset, "%s", file_name);
+ fl_color_print_line(f_standard_error, context.error, context.reset, "'.");
+ return;
+ }
+
+ if (error == f_invalid_directory) {
+ fl_color_print(f_standard_error, context.error, context.reset, "ERROR: Invalid directory while trying to access file '");
+ fl_color_print(f_standard_error, context.notable, context.reset, "%s", file_name);
+ fl_color_print_line(f_standard_error, context.error, context.reset, "'.");
+ return;
+ }
+
+ if (error == f_access_denied) {
+ fl_color_print(f_standard_error, context.error, context.reset, "ERROR: Access denied while trying to access file '");
+ fl_color_print(f_standard_error, context.notable, context.reset, "%s", file_name);
+ fl_color_print_line(f_standard_error, context.error, context.reset, "'.");
+ return;
+ }
+
+ if (error == f_loop) {
+ fl_color_print(f_standard_error, context.error, context.reset, "ERROR: Loop while trying to access file '");
+ fl_color_print(f_standard_error, context.notable, context.reset, "%s", file_name);
+ fl_color_print_line(f_standard_error, context.error, context.reset, "'.");
+ return;
+ }
+
+ fl_color_print(f_standard_error, context.error, context.reset, "UNKNOWN ERROR: (");
+ fl_color_print(f_standard_error, context.notable, context.reset, "%d", error);
+ fl_color_print(f_standard_error, context.error, context.reset, ") occurred for file '");
+ fl_color_print(f_standard_error, context.notable, context.reset, "%s", file_name);
+ fl_color_print_line(f_standard_error, context.error, context.reset, "'.");
+ }
+#endif // _di_bit_dump_print_file_error_