From: Kevin Day Date: Tue, 28 Feb 2012 01:43:54 +0000 (-0600) Subject: Import Commit: mass import fll project X-Git-Tag: 0.3.x~23 X-Git-Url: https://git.kevux.org/?a=commitdiff_plain;h=refs%2Fheads%2F0.2;p=fll Import Commit: mass import fll project This is not an import from the svn repository, but instead an import from the latest individual 0.2.* release for each project. This also has a few patches that I had applied or backported from kevux to fix bugs in the latest official releases. I did this because I am completely out of sync with whatever I was doing in the project. I was probably in the middle of making some major changes, but I do not remember what they were. Therefore, I am starting on a hopefully stable base to pick up from. --- diff --git a/level_0/f_colors/c/colors.h b/level_0/f_colors/c/colors.h new file mode 100644 index 0000000..dc25807 --- /dev/null +++ b/level_0/f_colors/c/colors.h @@ -0,0 +1,145 @@ +/* FLL - Level 0 + * Project: Colors + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Provide basic color output support (linux & xterm) + * This is the Featureless LINUX Library, so there is no support for non-linux colors at this time. + */ +#ifndef _F_colors_h +#define _F_colors_h + +// fll-0 includes +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_f_color_max_size_ + #define f_color_max_size 7 +#endif // _di_f_color_max_size_ + +#ifndef _di_f_color_types_ + typedef f_min_u_int f_color_id; + + // f_color_id codes + #define f_color_linux 0 + #define f_color_xterminal 1 +#endif // _di_f_color_types_ + +// the purpose behind these data types are not to dynamically allocate data +// instead, they are intended to only point to existing data, so these should neither be allocated nor deallocated +#ifndef _di_f_color_control_ + typedef struct f_color_control { + const f_autochar *bold; + const f_autochar *underline; + const f_autochar *blink; + const f_autochar *reverse; + const f_autochar *conceal; + } f_color_control; + + #define f_color_control_names_initialize { "bold", "underline", "blink", "reverse", "conceal" } +#endif // _di_f_color_control_ + +#ifndef _di_f_color_standard_io_ + typedef struct { + const f_autochar *message; + const f_autochar *warning; + const f_autochar *error; + const f_autochar *strong_message; // an emphasized message + const f_autochar *strong_warning; // an emphasized warning + const f_autochar *strong_error; // an emphasized error + } f_color_standard_io; + + #define f_color_standard_io_names_initialize { "message", "warning", "error", "strong_message", "strong_warning", "strong_error" } +#endif // _di_f_color_standard_io_ + +#ifndef _di_f_color_help_ + typedef struct { + const f_autochar *title; // name printed + const f_autochar *version; // version printed + const f_autochar *topic; // topic such as 'Usage' + const f_autochar *command; // color for a specific command, such as '-h' + const f_autochar *syntax; // color for syntax, such as '[' and '<' + const f_autochar *alert; // some form of alert such as 'Not Implemented Yet' + const f_autochar *comment; // not quite important text, but still should be seen + const f_autochar *standard; // the normal text color + const f_autochar *emphasize; // make sure something stands out to emphasize it + } f_color_help; + + #define f_color_help_names_initialize { "title", "version", "topic", "command", "syntax", "alert", "comment", "standard", "emphasize" } +#endif // _di_f_color_help_ + +#ifndef _di_f_colors_format_ + typedef struct { + const f_autochar *begin; + const f_autochar *medium; + const f_autochar *end; + } f_colors_format; + + #define f_colors_format_initialize_linux { "\033[", ";", "m" } + #define f_colors_format_initialize_xterminal { "\033[", ";", "m" } +#endif // _di_f_colors_format_ + +#ifndef _di_f_colors_ + typedef struct { + const f_autochar *reset; + const f_autochar *bold; + const f_autochar *underline; + const f_autochar *blink; + const f_autochar *reverse; + const f_autochar *conceal; + const f_autochar *black; + const f_autochar *red; + const f_autochar *green; + const f_autochar *yellow; + const f_autochar *blue; + const f_autochar *purple; + const f_autochar *teal; + const f_autochar *white; + const f_autochar *black_bg; + const f_autochar *red_bg; + const f_autochar *green_bg; + const f_autochar *yellow_bg; + const f_autochar *blue_bg; + const f_autochar *purple_bg; + const f_autochar *teal_bg; + const f_autochar *white_bg; + const f_autochar *bright_black; + const f_autochar *bright_red; + const f_autochar *bright_green; + const f_autochar *bright_yellow; + const f_autochar *bright_blue; + const f_autochar *bright_purple; + const f_autochar *bright_teal; + const f_autochar *bright_white; + const f_autochar *bright_black_bg; + const f_autochar *bright_red_bg; + const f_autochar *bright_green_bg; + const f_autochar *bright_yellow_bg; + const f_autochar *bright_blue_bg; + const f_autochar *bright_purple_bg; + const f_autochar *bright_teal_bg; + const f_autochar *bright_white_bg; + } f_colors; + + #define f_colors_initialize_linux { "0", "1", "4", "5", "7", "8", "30", "31", "32", "33", "34", "35", "36", "37", "40", "41", "42", "43", "44", "45", "46", "47", "30", "31", "32", "33", "34", "35", "36", "37", "40", "41", "42", "43", "44", "45", "46", "47" } + #define f_colors_initialize_xterminal { "0", "1", "4", "5", "7", "8", "30", "31", "32", "33", "34", "35", "36", "37", "40", "41", "42", "43", "44", "45", "46", "47", "90", "91", "92", "93", "94", "95", "96", "97", "100", "101", "102", "103", "104", "105", "106", "107" } +#endif // _di_f_colors_ + +#ifndef _di_f_default_colors_ + static const f_colors_format f_colors_format_linux = f_colors_format_initialize_linux; + static const f_colors_format f_colors_format_xterminal = f_colors_format_initialize_xterminal; + static const f_colors f_colors_linux = f_colors_initialize_linux; + static const f_colors f_colors_xterminal = f_colors_initialize_xterminal; +#endif // _di_f_default_colors_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _F_colors_h diff --git a/level_0/f_console/c/console.c b/level_0/f_console/c/console.c new file mode 100644 index 0000000..ed634c2 --- /dev/null +++ b/level_0/f_console/c/console.c @@ -0,0 +1,60 @@ +/* FLL - Level 0 + * Project: Console + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_f_console_identify_ + f_return_status f_console_identify(const f_string input, f_console_id *result){ + #ifndef _di_level_0_parameter_checking_ + if (result == f_null) return f_invalid_parameter; + #endif // _di_level_0_parameter_checking_ + + const f_string_length length = strnlen(input, 4); + + if (length == 0){ + *result = f_console_none; + return f_none; + } + + if (input[0] == f_console_symbol_enable){ + if (length > 1){ + if (input[1] == f_console_symbol_enable){ + if (length > 2){ + if (input[2] == f_console_symbol_enable){ + if (length > 3){ + *result = f_console_extra_enable; + } else *result = f_console_empty_extra_enable; + } else *result = f_console_long_enable; + } else *result = f_console_empty_long_enable; + } else *result = f_console_short_enable; + } else *result = f_console_empty_short_enable; + } else if (input[0] == f_console_symbol_disable){ + if (length > 1){ + if (input[1] == f_console_symbol_disable){ + if (length > 2){ + if (input[2] == f_console_symbol_disable){ + if (length > 3){ + *result = f_console_extra_disable; + } else *result = f_console_empty_extra_disable; + } else *result = f_console_long_disable; + } else *result = f_console_empty_long_disable; + } else *result = f_console_short_disable; + } else *result = f_console_empty_short_disable; + } else { + *result = f_console_none; + } + + return f_none; + } +#endif // _di_f_console_identify_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_0/f_console/c/console.h b/level_0/f_console/c/console.h new file mode 100644 index 0000000..130ec75 --- /dev/null +++ b/level_0/f_console/c/console.h @@ -0,0 +1,158 @@ +/* FLL - Level 0 + * Project: Console + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Some console input/output commands + */ +#ifndef _F_console_h +#define _F_console_h + +// libc include +#include + +// fll-0 includes +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +// result values that represent the type of command found +#ifndef _di_f_console_ids_ + #define f_console_none 0 + #define f_console_short_enable 1 + #define f_console_short_disable 2 + #define f_console_long_enable 3 + #define f_console_long_disable 4 + #define f_console_extra_enable 5 + #define f_console_extra_disable 6 + #define f_console_empty_short_enable 7 + #define f_console_empty_short_disable 8 + #define f_console_empty_long_enable 9 + #define f_console_empty_long_disable 10 + #define f_console_empty_extra_enable 11 + #define f_console_empty_extra_disable 12 +#endif // _di_f_console_ids_ + +// the symbols passed to the program for option handling +#ifndef _di_f_console_symbols_ + #define f_console_symbol_enable '-' // this will be processed as an integer and therefore must not be string + #define f_console_symbol_disable '+' // this will be processed as an integer and therefore must not be string + #define f_console_symbol_short_enable "-" + #define f_console_symbol_short_disable "+" + #define f_console_symbol_long_enable "--" + #define f_console_symbol_long_disable "++" + #define f_console_symbol_extra_enable "---" + #define f_console_symbol_extra_disable "+++" +#endif // _di_f_console_symbols_ + +// create some standard command line parameter options required by the kevux/fss/fll specifications +#ifndef _di_f_standard_console_parameters_ + #define f_console_standard_short_help "h" + #define f_console_standard_short_light "l" // usage: +l + #define f_console_standard_short_no_color "n" // usage: +n + #define f_console_standard_short_version "v" + + #define f_console_standard_long_help "help" + #define f_console_standard_long_light "light" + #define f_console_standard_long_no_color "no_color" + #define f_console_standard_long_version "version" +#endif // _di_f_standard_console_parameters_ + +// the maximum size for a single parameter (this should be hellishly more than enough) +#ifndef _di_f_console_max_size_ + #define f_console_max_size f_string_max_size +#endif // _di_f_console_max_size_ + +#ifndef _di_f_console_default_allocation_step_ + #define f_console_default_allocation_step f_memory_default_allocation_step +#endif // _di_f_console_default_allocation_step_ + +#ifndef _di_f_console_types_ + typedef f_min_u_short f_console_id; + + enum { + f_console_result_none, + f_console_result_found, + f_console_result_additional, // something was found and extra data exists (such as '-f filename', filename would be the extra data) + }; + + enum { + f_console_type_normal, + f_console_type_inverse, + f_console_type_other, + }; +#endif // _di_f_console_types_ + +#ifndef _di_f_console_parameter_ + typedef struct { + const f_autochar *symbol_short; + const f_autochar *symbol_long; + const f_autochar *symbol_extra; + const f_autochar *symbol_other; + + const f_bool has_additional; + const f_u_int type; + f_u_int result; + f_string_length additional; + f_string_length length; + } f_console_parameter; + + #define f_console_parameter_initialize(symbol_short, symbol_long, symbol_extra, symbol_other, has_additional, type_value, length) \ + { symbol_short, symbol_long, symbol_extra, symbol_other, has_additional, type_value, f_console_result_none, 0, length } +#endif // _di_f_console_parameter_ + +#ifndef _di_f_console_identify_ + // This is used to help standardize a single method of handling command line option parsing. + // This should allow for every single command line program to use the same form of syntax for command line options. + extern f_return_status f_console_identify(const f_string input, f_console_id *result); +#endif // _di_f_console_identify_ + +// perform checks against short & long options to see if the string is one of them (normal) +#ifndef _di_f_console_is_enable_ + #define f_console_is_enable(result, string, short_option, long_option, max_length) \ + ((result == f_console_short_enable && strncmp(string, short_option, 1) == 0) || \ + (result == f_console_long_enable && strncmp(string, long_option, max_length) == 0)) +#endif // _di_f_console_is_enable_ + +// perform checks against short & long options to see if the string is one of them (inverse) +#ifndef _di_f_console_is_disable_ + #define f_console_is_disable(result, string, short_option, long_option, max_length) \ + ((result == f_console_short_disable && strncmp(string, short_option, 1) == 0) || \ + (result == f_console_long_disable && strncmp(string, long_option, max_length) == 0)) +#endif // _di_f_console_is_disable_ + +// perform checks against extra option to see if the string is one of them (normal) +#ifndef _di_f_console_is_extra_enable_ + #define f_console_is_extra_enable(result, string, extra_option, max_length) \ + (result == f_console_extra_enable && strncmp(string, extra_option, max_length) == 0) +#endif // _di_f_console_is_extra_enable_ + +// perform checks against extra option to see if the string is one of them (inverse) +#ifndef _di_f_console_is_extra_disable_ + #define f_console_is_extra_disable(result, string, extra_option, max_length) \ + (result == f_console_extra_disable && strncmp(string, extra_option, max_length) == 0) +#endif // _di_f_console_is_extra_disable_ + +// perform checks against empty options to see if the string is one of them (normal) +#ifndef _di_f_console_is_empty_enable_ + #define f_console_is_empty_enable(result, string) \ + (result == f_console_empty_short_enable || result == f_console_empty_long_enable || result == f_console_empty_extra_enable) +#endif // _di_f_console_is_empty_enable_ + +// perform checks against empty options to see if the string is one of them (inverse) +#ifndef _di_f_console_is_empty_disable_ + #define f_console_is_empty_disable(result, string) \ + (result == f_console_empty_short_disable || result == f_console_empty_long_disable || result == f_console_empty_extra_disable) +#endif // _di_f_console_is_empty_disable_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _F_console_h diff --git a/level_0/f_conversion/c/conversion.c b/level_0/f_conversion/c/conversion.c new file mode 100644 index 0000000..876fa15 --- /dev/null +++ b/level_0/f_conversion/c/conversion.c @@ -0,0 +1,203 @@ +/* FLL - Level 0 + * Project: Conversion + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_f_is_digit_ + f_return_status f_is_digit(const f_autochar character){ + + // at this point, it seems that it would incur more overhead to use the libc isdigit here, so just use one less call and test it here + switch(character){ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return f_true; + default: + return f_false; + } + + } +#endif // _di_f_is_digit_ + +#ifndef _di_f_is_hexdigit_ + f_return_status f_is_hexdigit(const f_autochar character){ + + switch(character){ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + return f_true; + default: + return f_false; + } + } +#endif // _di_f_is_hexdigit_ + +#ifndef _di_f_character_to_digit_ + f_return_status f_character_to_digit(const f_autochar character, f_u_long *digit){ + #ifndef _di_level_0_parameter_checking_ + if (digit == f_null) return f_invalid_parameter; + #endif // _di_level_0_parameter_checking_ + + switch(character){ + case '0': *digit = 0; break; + case '1': *digit = 1; break; + case '2': *digit = 2; break; + case '3': *digit = 3; break; + case '4': *digit = 4; break; + case '5': *digit = 5; break; + case '6': *digit = 6; break; + case '7': *digit = 7; break; + case '8': *digit = 8; break; + case '9': *digit = 9; break; + default: + return f_no_data; + } + + return f_none; + } +#endif // _di_f_character_to_digit_ + +#ifndef _di_f_character_to_hexdigit_ + f_return_status f_character_to_hexdigit(const f_autochar character, f_u_long *digit){ + #ifndef _di_level_0_parameter_checking_ + if (digit == f_null) return f_invalid_parameter; + #endif // _di_level_0_parameter_checking_ + + switch(character){ + case '0': *digit = 0; break; + case '1': *digit = 1; break; + case '2': *digit = 2; break; + case '3': *digit = 3; break; + case '4': *digit = 4; break; + case '5': *digit = 5; break; + case '6': *digit = 6; break; + case '7': *digit = 7; break; + case '8': *digit = 8; break; + case '9': *digit = 9; break; + case 'A': *digit = 10; break; + case 'B': *digit = 11; break; + case 'C': *digit = 12; break; + case 'D': *digit = 13; break; + case 'E': *digit = 14; break; + case 'F': *digit = 15; break; + case 'a': *digit = 10; break; + case 'b': *digit = 11; break; + case 'c': *digit = 12; break; + case 'd': *digit = 13; break; + case 'e': *digit = 14; break; + case 'f': *digit = 15; break; + default: + return f_no_data; + } + + return f_none; + } +#endif // _di_f_character_to_hexdigit_ + +#ifndef _di_f_string_to_digit_ + f_return_status f_string_to_digit(const f_string string, f_u_long *digit, const f_string_location location){ + #ifndef _di_level_0_parameter_checking_ + if (digit == f_null) return f_invalid_parameter; + if (location.start < 0) return f_invalid_parameter; + if (location.stop <= location.start) return f_invalid_parameter; + if (string == 0) return f_invalid_parameter; + #endif // _di_level_0_parameter_checking_ + + f_string_length current_location = location.start; + f_u_long scale = 0; + f_u_long temp_digit = 0; + + while(current_location < location.stop){ + if (f_character_to_digit(string[current_location], &temp_digit) == f_none){ + + // when the scale exists, then we need to make the number larger, for this function the scale is base 10 + if (scale > 0){ + *digit = 10 * *digit; + *digit += temp_digit; + } else { + scale = 1; + *digit = temp_digit; + } + } else { + break; + } + + ++current_location; + } + + return f_none; + } +#endif // _di_f_string_to_digit_ + +#ifndef _di_f_string_to_hexdigit_ + f_return_status f_string_to_hexdigit(const f_string string, f_u_long *digit, const f_string_location location){ + #ifndef _di_level_0_parameter_checking_ + if (digit == f_null) return f_invalid_parameter; + if (location.start < 0) return f_invalid_parameter; + if (location.stop <= location.start) return f_invalid_parameter; + if (string == 0) return f_invalid_parameter; + #endif // _di_level_0_parameter_checking_ + + f_string_length current_location = location.start; + f_u_long scale = 0; + f_u_long temp_digit = 0; + + while(current_location < location.stop){ + if (f_character_to_hexdigit(string[current_location], &temp_digit) == f_none){ + + // when the scale exists, then we need to make the number larger, for this function the scale is base 16 + if (scale > 0){ + *digit <<= 4; + *digit += temp_digit; + } else { + scale = 1; + *digit = temp_digit; + } + } else { + break; + } + + ++current_location; + } + + return f_none; + } +#endif // _di_f_string_to_hexdigit_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_0/f_conversion/c/conversion.h b/level_0/f_conversion/c/conversion.h new file mode 100644 index 0000000..db77aef --- /dev/null +++ b/level_0/f_conversion/c/conversion.h @@ -0,0 +1,72 @@ +/* FLL - Level 0 + * Project: Conversion + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Provide means to convert one data type to another, such as a string to an integer + * Provide means to identify a digit or a hexadecimal digit (hexdigit) + * In the future this will have to link to locale support, due to interpeting strings + * + * Possible error values on return: + * f_warn - a possible problem, but not an error (warning) + * f_critical - an error + * f_unknown - an unknown error + * f_invalid_parameter - a parameter sent to this function is invalid, error + * f_invalid_syntax - syntax for data sent to this is invalid, error + * f_invalid_data - something is wrong with the data sent to this function, error + * f_no_data - something is wrong with the data sent to this function, warning + * f_none - no errors or warnings + */ +#ifndef _F_conversion_h +#define _F_conversion_h + +// fll includes +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_f_is_digit_ + // convert a single character into the digit that it represents + extern f_return_status f_is_digit(const f_autochar character); +#endif // _di_f_is_digit_ + +#ifndef _di_f_is_hexdigit_ + // convert a single character into the hexidecimal digit that it represents + extern f_return_status f_is_hexdigit(const f_autochar character); +#endif // _di_f_is_hexdigit_ + +#ifndef _di_f_character_to_digit_ + // convert a single character into the digit that it represents + extern f_return_status f_character_to_digit(const f_autochar character, f_u_long *digit); +#endif // _di_f_character_to_digit_ + +#ifndef _di_f_character_to_hexdigit_ + // convert a single character into the hexidecimal digit that it represents + extern f_return_status f_character_to_hexdigit(const f_autochar character, f_u_long *digit); +#endif // _di_f_character_to_hexdigit_ + +#ifndef _di_f_string_to_digit_ + // works like atoi, except there is a start/stop range + // convert a series of positive numbers into a string, stopping at one of the following: EOS, max_length, or a non-digit + // will not process signed statuses (+/-) + extern f_return_status f_string_to_digit(const f_string string, f_u_long *digit, const f_string_location location); +#endif // _di_f_string_to_digit_ + +#ifndef _di_f_string_to_hexdigit_ + // works like atoi, except there is a start/stop range and that this is for hexidecimal digits + // convert a series of positive numbers into a string, stopping at one of the following: EOS, max_length, or a non-hexdigit + // will not process signed statuses (+/-) + extern f_return_status f_string_to_hexdigit(const f_string string, f_u_long *digit, const f_string_location location); +#endif // _di_f_string_to_hexdigit_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _F_conversion_h diff --git a/level_0/f_errors/bash/errors.sh b/level_0/f_errors/bash/errors.sh new file mode 100644 index 0000000..1ff7203 --- /dev/null +++ b/level_0/f_errors/bash/errors.sh @@ -0,0 +1,11 @@ +# FLL - Level 0 +# Project: Errors +# Version: 0.2.0 +# Licenses: flll, lgplv2.1 +# Programmers: Kevin Day +# Documentation: Provides error codes + +f_true=1 +f_false=0 +f_warn=2 +f_unknown=3 diff --git a/level_0/f_errors/c/errors.h b/level_0/f_errors/c/errors.h new file mode 100644 index 0000000..0f70729 --- /dev/null +++ b/level_0/f_errors/c/errors.h @@ -0,0 +1,207 @@ +/* FLL - Level 0 + * Project: Errors + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Provides error definitions + */ +#ifndef _F_errors_h +#define _F_errors_h + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_f_macro_test_for_basic_errors_ + #define f_macro_test_for_basic_errors(potential_error) \ + ( potential_error == f_critical || \ + potential_error == f_unknown || \ + potential_error == f_unsupported || \ + potential_error == f_invalid_parameter || \ + potential_error == f_invalid_syntax || \ + potential_error == f_invalid_data || \ + potential_error == f_output_error || \ + potential_error == f_does_not_exist || \ + potential_error == f_failure) +#endif // _di_f_macro_test_for_basic_errors_ + +#ifndef _di_f_macro_test_for_allocation_errors_ + // FIXME: invalid_parameter was temporarily added here so that parameter checking could be corrected for all allocations and deallocations + #define f_macro_test_for_allocation_errors(potential_error) \ + ( potential_error == f_allocation_error || \ + potential_error == f_reallocation_error || \ + potential_error == f_file_allocation_error || \ + potential_error == f_file_reallocation_error || \ + potential_error == f_directory_allocation_error || \ + potential_error == f_invalid_parameter || \ + potential_error == f_directory_reallocation_error ) +#endif // _di_f_macro_test_for_allocation_errors_ + +#ifndef _di_f_macro_test_for_non_errors_ + #define f_macro_test_for_non_errors(potential_error) \ + ( potential_error == f_true || \ + potential_error == f_false || \ + potential_error == f_warn || \ + potential_error == f_no_data || \ + potential_error == f_no_data_on_eos || \ + potential_error == f_no_data_on_eof || \ + potential_error == f_no_data_on_stop || \ + potential_error == f_none_on_eof || \ + potential_error == f_none_on_eos || \ + potential_error == f_none_on_stop || \ + potential_error == f_less_than || \ + potential_error == f_equal_to || \ + potential_error == f_not_equal_to || \ + potential_error == f_greater_than || \ + potential_error == f_none ) +#endif // _di_f_macro_test_for_non_errors_ + +#ifndef _di_macro_f_test_for_file_errors_ + #define f_macro_test_for_file_errors(potential_error) \ + ( potential_error == f_file_seek_error || \ + potential_error == f_file_read_error || \ + potential_error == f_file_write_error || \ + potential_error == f_file_flush_error || \ + potential_error == f_file_purge_error || \ + potential_error == f_file_open_error || \ + potential_error == f_file_close_error || \ + potential_error == f_file_synchronize_error || \ + potential_error == f_file_descriptor_error || \ + potential_error == f_file_not_found || \ + potential_error == f_file_is_empty || \ + potential_error == f_file_not_open ) +#endif // _di_f_macro_test_for_file_errors_ + +#ifndef _di_f_macro_test_for_directory_errors_ + #define f_macro_test_for_directory_errors(parameter) \ + ( potential_error == f_directory_seek_error || \ + potential_error == f_directory_read_error || \ + potential_error == f_directory_write_error || \ + potential_error == f_directory_flush_error || \ + potential_error == f_directory_purge_error || \ + potential_error == f_directory_open_error || \ + potential_error == f_directory_close_error || \ + potential_error == f_directory_synchronize_error || \ + potential_error == f_directory_descriptor_error || \ + potential_error == f_directory_not_found || \ + potential_error == f_directory_is_empty || \ + potential_error == f_directory_not_open ) +#endif // _di_f_macro_test_for_directory_errors_ + +// use of an enumerator makes more sense here than explicitly defining every error code +enum { + #ifndef _di_f_error_booleans_ + f_false, + f_true, + #endif // _di_f_error_booleans_ + + #ifndef _di_f_error_basic_ + f_none, + f_dummy, // to only be used as a placeholder + f_warn, // warning + f_critical, + f_unknown, // For the "code should never get here" errors. (this is an EMERGENCY error) + f_unsupported, + f_invalid_parameter, + f_invalid_syntax, + f_invalid_data, + f_no_data, // warning + f_output_error, + f_does_not_exist, + f_failure, + #endif // _di_f_error_basic_ + + #ifndef _di_f_error_digits_ + f_underflow, + f_overflow, + f_divide_by_zero, + f_cannot_be_negative, + f_cannot_be_positive, + f_cannot_be_zero, + #endif // _di_f_error_digits_ + + #ifndef _di_f_error_buffers_ + f_no_data_on_eof, // warning + f_no_data_on_eos, // warning + f_no_data_on_stop, // warning + f_none_on_eof, // warning + f_none_on_eos, // warning + f_none_on_stop, // "stop" location was reached + f_error_on_eof, + f_error_on_eos, + f_error_on_stop, + f_string_too_small, + f_string_too_large, + f_unterminated_nest, + f_unterminated_nest_on_eos, + f_unterminated_nest_on_eof, + f_unterminated_nest_on_stop, + f_unterminated_group, + f_unterminated_group_on_eos, + f_unterminated_group_on_eof, + f_unterminated_group_on_stop, + #endif // _di_f_error_buffers_ + + #ifndef _di_f_error_allocation_ + f_allocation_error, + f_reallocation_error, + #endif // _di_f_error_allocation_ + + #ifndef _di_f_error_fork_ + f_fork_failed, + #endif // _di_f_error_fork_ + + #ifndef _di_f_error_file_ + f_file_seek_error, + f_file_read_error, + f_file_write_error, + f_file_flush_error, + f_file_purge_error, + f_file_open_error, + f_file_close_error, + f_file_synchronize_error, + f_file_descriptor_error, + f_file_not_found, + f_file_is_empty, + f_file_not_open, + f_file_allocation_error, + f_file_reallocation_error, + f_file_error, + #endif // _di_f_error_file_ + + // most of these are a guess until I get around to researching & implementing linux directory I/O + #ifndef _di_f_error_directory_ + f_directory_read_error, + f_directory_write_error, + f_directory_flush_error, + f_directory_purge_error, + f_directory_open_error, + f_directory_close_error, + f_directory_synchronize_error, + f_directory_descriptor_error, + f_directory_not_found, + f_directory_is_empty, + f_directory_not_open, + f_directory_allocation_error, + f_directory_reallocation_error, + f_directory_error, + #endif // _di_f_error_directory_ + + #ifndef _di_f_error_non_ + f_less_than, + f_equal_to, + f_not_equal_to, + f_greater_than, + #endif // _di_f_error_non_ + + // required + f_last_error_code +}; // enum + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _F_errors_h diff --git a/level_0/f_file/c/file.c b/level_0/f_file/c/file.c new file mode 100644 index 0000000..2c64caf --- /dev/null +++ b/level_0/f_file/c/file.c @@ -0,0 +1,136 @@ +/* FLL - Level 0 + * Project: File + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Provides structures and data types for a file I/O. + * Provides operations for opening/closing files + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_f_file_open_ + f_return_status f_file_open(f_file *file_information, const f_string filename){ + #ifndef _di_level_0_parameter_checking_ + if (file_information == f_null) return f_invalid_parameter; + #endif // _di_level_0_parameter_checking_ + + // if file->mode is unset, then this may cause a segfault, depending on whether or not the libc will handle this appropriately + if (file_information->mode == 0) return f_invalid_parameter; + + file_information->file = fopen(filename, file_information->mode); + + if (file_information->file == 0) return f_file_not_found; + if (ferror(file_information->file) != 0) return f_file_open_error; + + file_information->id = fileno(file_information->file); + + if (file_information->id == -1) return f_file_descriptor_error; + + return f_none; + } +#endif // _di_f_file_open_ + +#ifndef _di_f_file_close_ + f_return_status f_file_close(f_file *file_information){ + #ifndef _di_level_0_parameter_checking_ + if (file_information == f_null) return f_invalid_parameter; + #endif // _di_level_0_parameter_checking_ + + if (file_information->file == 0) return f_file_not_open; + + // if we were given a file descriptor as well, make sure to flush all changes to the disk that are not flushed by the 'fflush()' command + if (file_information->id != 0){ + // make sure all unfinished data gets completed + if (fsync(file_information->id) != 0) return f_file_synchronize_error; + } + + if (fclose(file_information->file) == 0){ + file_information->file = 0; + return f_none; + } + else return f_file_close_error; + } +#endif // _di_f_file_close_ + +#ifndef _di_f_file_flush_ + f_return_status f_file_flush(f_file *file_information){ + #ifndef _di_level_0_parameter_checking_ + if (file_information == f_null) return f_invalid_parameter; + #endif // _di_level_0_parameter_checking_ + + if (file_information->file == 0) return f_file_not_open; + + if (fflush(file_information->file) == 0) return f_none; + else return f_file_flush_error; + } +#endif // _di_f_file_flush_ + +#ifndef _di_f_file_read_ + f_return_status f_file_read(f_file *file_information, f_dynamic_string *buffer, const f_file_position location){ + #ifndef _di_level_0_parameter_checking_ + if (file_information == f_null) return f_invalid_parameter; + if (location.buffer_start < 0) return f_invalid_parameter; + if (location.file_start < 0) return f_invalid_parameter; + if (location.total_elements < 0) return f_invalid_parameter; + + // when the available buffer size is smaller than the total elements, then there is not enough allocated memory available to read the file + if (location.total_elements > 0){ + if (buffer->size - location.buffer_start < location.total_elements) return f_invalid_parameter; + } + #endif // _di_level_0_parameter_checking_ + + if (file_information->file == 0) return f_file_not_open; + + // first seek to 'where' we need to begin the read + f_u_long current_file_position = ftell(file_information->file); + if (current_file_position == (f_u_long) -1) return f_file_seek_error; + + f_s_int result = 0; + + if (current_file_position > location.file_start){ + result = f_file_seek_from_current(file_information->file, file_information->byte_size * (0 - (current_file_position - location.file_start))); + } else if (current_file_position < location.file_start){ + result = f_file_seek_from_current(file_information->file, file_information->byte_size * (location.file_start - current_file_position)); + } + + if (result != 0) return f_file_seek_error; + + // now do the actual read + if (location.total_elements == 0){ + result = fread(buffer->string + location.buffer_start, file_information->byte_size, buffer->size - 1, file_information->file); + } else { + result = fread(buffer->string + location.buffer_start, file_information->byte_size, location.total_elements, file_information->file); + } + + if (file_information->file == 0) return f_file_read_error; + if (ferror(file_information->file) != 0) return f_file_read_error; + + // now save how much of our allocated buffer is actually used + // also make sure that we aren't making used space vanish + if (location.buffer_start + result > buffer->used){ + buffer->used = location.buffer_start + result; + } + + // append an EOS only when the total elements were set to 0 + if (location.total_elements == 0){ + buffer->string[buffer->used] = f_eos; + } + + // make sure to communicate that we are done without a problem and the eof was reached + if (feof(file_information->file)){ + return f_none_on_eof; + } + + return f_none; + } +#endif // _di_f_file_read_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_0/f_file/c/file.h b/level_0/f_file/c/file.h new file mode 100644 index 0000000..88be157 --- /dev/null +++ b/level_0/f_file/c/file.h @@ -0,0 +1,211 @@ +/* FLL - Level 0 + * Project: File + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Provides structures and data types for a file I/O. + * Provides operations for opening/closing files + */ +#ifndef _F_file_h +#define _F_file_h + +// libc includes +#include +#include +#include +#include +#include + +// fll-0 includes +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_f_file_types_ + typedef f_s_int f_file_id; + typedef f_string f_file_mode; + typedef f_mode_t f_file_mask; + + #define f_file_default_read_size 4096 // default to 4k read sizes + #define f_file_max_path_length 1024 +#endif // _di_f_file_types_ + +#ifndef _di_f_file_oldstyle_modes_ + #define f_file_read_only "r" + #define f_file_write_only "w" + #define f_file_read_write "rw" +#endif // _di_f_file_oldstyle_modes_ + +#ifndef _di_f_file_seeks_ + #define f_file_seek_from_beginning(file, bytes) fseek(file, bytes, SEEK_SET) + #define f_file_seek_from_current(file, bytes) fseek(file, bytes, SEEK_CUR) + #define f_file_seek_from_end(file, bytes) fseek(file, bytes, SEEK_END) +#endif // _di_f_file_seeks_ + +#ifndef _di_f_file_ + typedef struct { + f_file_id id; // file descriptor + f_file_type file; // the file data type + f_file_mode mode; // how the file is to be accessed (or is being accessed) + f_size_t byte_size; // how many bytes to use on each read/write (for normal string handling this should be sizeof(f_string) + } f_file; + + #define f_file_initialize { 0, 0, (f_file_mode) f_file_read_only, sizeof(f_autochar) } +#endif // _di_f_file_ + +#ifndef _di_f_file_position_ + // buffer_start designate where to start writing to the buffer + // file_start is the positions where to begin reading the file + // total_elements is the total number of elements to read from the file into the buffer + // if total_elements is set to 0, then this means to buffer the entire file no matter how big it is (crazy?) + typedef struct { + f_string_length buffer_start; + f_string_length file_start; + f_string_length total_elements; + } f_file_position; + + #define f_file_position_initialize { 0, 0, 0 } +#endif // _di_f_file_position_ + +// TODO: the information below needs to be confirmed and updated accordingly.. +#ifndef _di_f_file_modes_ + + // file open modes + #define f_file_mode_read_only O_RDONLY + #define f_file_mode_write_only O_WRONLY + #define f_file_mode_read_write O_RDWR + #define f_file_mode_create O_CREAT + #define f_file_mode_exclusive O_EXCL + #define f_file_mode_no_tty O_NOCTTY + #define f_file_mode_truncate O_TRUNC + #define f_file_mode_append O_APPEND + #define f_file_mode_non_blocking O_NONBLOCK + #define f_file_mode_synchronous O_SYNC + #define f_file_mode_no_follow O_NOFOLLOW + #define f_file_mode_directory O_DIRECTORY + #define f_file_mode_direct_io O_DIRECT + #define f_file_mode_asynchronous O_ASYNC + #define f_file_mode_large_file O_LARGEFILE + + // file open modes pre-combined with create + #define f_file_mode_create_ro (O_CREAT | O_RDONLY) + #define f_file_mode_create_wo (O_CREAT | O_WRONLY) + #define f_file_mode_create_rw (O_CREAT | O_RDRW) + + // file open modes pre-combined will fail if file exists + #define f_file_mode_create_new_ro (O_CREAT | O_EXCL | O_RDONLY) + #define f_file_mode_create_new_wo (O_CREAT | O_EXCL | O_WRONLY) + #define f_file_mode_create_new_rw (O_CREAT | O_EXCL | O_RDRW) + + // file open modes pre-combined with synchronous io + #define f_file_mode_sync_ro (O_SYNC | O_RDONLY) + #define f_file_mode_sync_wo (O_SYNC | O_WRONLY) + #define f_file_mode_sync_rw (O_SYNC | O_RDRW) + #define f_file_mode_sync_create_ro (O_SYNC | O_CREAT | O_RDONLY) + #define f_file_mode_sync_create_wo (O_SYNC | O_CREAT | O_WRONLY) + #define f_file_mode_sync_create_rw (O_SYNC | O_CREAT | O_RDRW) + #define f_file_mode_sync_create_new_ro (O_SYNC | O_CREAT | O_EXCL | O_RDONLY) + #define f_file_mode_sync_create_new_wo (O_SYNC | O_CREAT | O_EXCL | O_WRONLY) + #define f_file_mode_sync_create_new_rw (O_SYNC | O_CREAT | O_EXCL | O_RDRW) + + // file open modes pre-combined with asynchronous io + #define f_file_mode_async_ro (O_ASYNC | O_RDONLY) + #define f_file_mode_async_wo (O_ASYNC | O_WRONLY) + #define f_file_mode_async_rw (O_ASYNC | O_RDRW) + #define f_file_mode_async_create_ro (O_ASYNC | O_CREAT | O_RDONLY) + #define f_file_mode_async_create_wo (O_ASYNC | O_CREAT | O_WRONLY) + #define f_file_mode_async_create_rw (O_ASYNC | O_CREAT | O_RDRW) + #define f_file_mode_async_create_new_ro (O_ASYNC | O_CREAT | O_EXCL | O_RDONLY) + #define f_file_mode_async_create_new_wo (O_ASYNC | O_CREAT | O_EXCL | O_WRONLY) + #define f_file_mode_async_create_new_rw (O_ASYNC | O_CREAT | O_EXCL | O_RDRW) + + // file open modes pre-combined with direct io (which works synchronously) + #define f_file_mode_direct_ro (O_DIRECT | O_RDONLY) + #define f_file_mode_direct_wo (O_DIRECT | O_WRONLY) + #define f_file_mode_direct_rw (O_DIRECT | O_RDRW) + #define f_file_mode_direct_create_ro (O_DIRECT | O_CREAT | O_RDONLY) + #define f_file_mode_direct_create_wo (O_DIRECT | O_CREAT | O_WRONLY) + #define f_file_mode_direct_create_rw (O_DIRECT | O_CREAT | O_RDRW) + #define f_file_mode_direct_create_new_ro (O_DIRECT | O_CREAT | O_EXCL | O_RDONLY) + #define f_file_mode_direct_create_new_wo (O_DIRECT | O_CREAT | O_EXCL | O_WRONLY) + #define f_file_mode_direct_create_new_rw (O_DIRECT | O_CREAT | O_EXCL | O_RDRW) + + // file open modes pre-combined with large_file + #define f_file_mode_large_ro (O_LARGEFILE | O_RDONLY) + #define f_file_mode_large_wo (O_LARGEFILE | O_WRONLY) + #define f_file_mode_large_rw (O_LARGEFILE | O_RDRW) + #define f_file_mode_large_sync_ro (O_LARGEFILE | O_SYNC | O_RDONLY) + #define f_file_mode_large_sync_wo (O_LARGEFILE | O_SYNC | O_WRONLY) + #define f_file_mode_large_sync_rw (O_LARGEFILE | O_SYNC | O_RDRW) + #define f_file_mode_large_sync_create_ro (O_LARGEFILE | O_SYNC | O_CREAT | O_RDONLY) + #define f_file_mode_large_sync_create_wo (O_LARGEFILE | O_SYNC | O_CREAT | O_WRONLY) + #define f_file_mode_large_sync_create_rw (O_LARGEFILE | O_SYNC | O_CREAT | O_RDRW) + #define f_file_mode_large_sync_create_new_ro (O_LARGEFILE | O_SYNC | O_CREAT | O_EXCL | O_RDONLY) + #define f_file_mode_large_sync_create_new_wo (O_LARGEFILE | O_SYNC | O_CREAT | O_EXCL | O_WRONLY) + #define f_file_mode_large_sync_create_new_rw (O_LARGEFILE | O_SYNC | O_CREAT | O_EXCL | O_RDRW) + #define f_file_mode_large_async_ro (O_LARGEFILE | O_ASYNC | O_RDONLY) + #define f_file_mode_large_async_wo (O_LARGEFILE | O_ASYNC | O_WRONLY) + #define f_file_mode_large_async_rw (O_LARGEFILE | O_ASYNC | O_RDRW) + #define f_file_mode_large_async_create_ro (O_LARGEFILE | O_ASYNC | O_CREAT | O_RDONLY) + #define f_file_mode_large_async_create_wo (O_LARGEFILE | O_ASYNC | O_CREAT | O_WRONLY) + #define f_file_mode_large_async_create_rw (O_LARGEFILE | O_ASYNC | O_CREAT | O_RDRW) + #define f_file_mode_large_async_create_new_ro (O_LARGEFILE | O_ASYNC | O_CREAT | O_EXCL | O_RDONLY) + #define f_file_mode_large_async_create_new_wo (O_LARGEFILE | O_ASYNC | O_CREAT | O_EXCL | O_WRONLY) + #define f_file_mode_large_async_create_new_rw (O_LARGEFILE | O_ASYNC | O_CREAT | O_EXCL | O_RDRW) + + // file permission modes + #define f_file_mode_owner_rwx S_IRWXU + #define f_file_mode_owner_r S_IRUSR + #define f_file_mode_owner_w S_IWUSR + #define f_file_mode_owner_x S_IXUSR + #define f_file_mode_owner_rw (S_IRUSR | S_IWUSR) + #define f_file_mode_owner_rx (S_IRUSR | S_IXUSR) + #define f_file_mode_owner_wx (S_IWUSR | S_IXUSR) + #define f_file_mode_group_rwx S_IRWXG + #define f_file_mode_group_r S_IRGRP + #define f_file_mode_group_w S_IWGRP + #define f_file_mode_group_x S_IXGRP + #define f_file_mode_group_rw (S_IRGRP | S_IWGRP) + #define f_file_mode_group_rx (S_IRGRP | S_IXGRP) + #define f_file_mode_group_wx (S_IWGRP | S_IXGRP) + #define f_file_mode_world_rwx S_IRWXO + #define f_file_mode_world_r S_IROTH + #define f_file_mode_world_w S_IWOTH + #define f_file_mode_world_x S_IXOTH + #define f_file_mode_world_rw (S_IROTH | S_IWOTH) + #define f_file_mode_world_rx (S_IROTH | S_IXOTH) + #define f_file_mode_world_wx (S_IWOTH | S_IXOTH) +#endif // _di_f_file_modes_ + +#ifndef _di_f_file_open_ + // open a particular file and save its stream + // filename = name of the file + extern f_return_status f_file_open(f_file *file_information, const f_string filename); +#endif // _di_f_file_open_ + +#ifndef _di_f_file_close_ + // close file + extern f_return_status f_file_close(f_file *file_information); +#endif // _di_f_file_close_ + +#ifndef _di_f_file_flush_ + // flush file + extern f_return_status f_file_flush(f_file *file_information); +#endif // _di_f_file_flush_ + +#ifndef _di_f_file_read_ + // read a given amount of data from the buffer, will auto-seek to where + extern f_return_status f_file_read(f_file *file_information, f_dynamic_string *buffer, const f_file_position location); +#endif // _di_f_file_read_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _F_file_h diff --git a/level_0/f_fss/c/fss.h b/level_0/f_fss/c/fss.h new file mode 100644 index 0000000..3c9b977 --- /dev/null +++ b/level_0/f_fss/c/fss.h @@ -0,0 +1,226 @@ +/* FLL - Level 0 + * Project: FSS + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Defines all datatypes to be used for/by project fss + * + * The purpose of compression is not to compression the entire file's contents but only and individual objects content, so the file is still partially readable + * NOTE: all start/stop locations must be defined as a (start < stop) and not (start <= stop), therefore if (start == stop) then stop + */ +#ifndef _F_fss_h +#define _F_fss_h + +// fll includes +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_f_fss_types_ + #define f_fss_comment '#' + #define f_fss_space ' ' + #define f_fss_space_holder '_' + #define f_fss_basic_open ' ' + #define f_fss_basic_close '\n' + #define f_fss_extended_open ' ' + #define f_fss_extended_close '\n' + #define f_fss_list_terminator '\n' + #define f_fss_basic_list_open ':' + #define f_fss_basic_list_close '\0' + #define f_fss_extended_list_open '{' + #define f_fss_extended_list_close '}' + #define f_fss_type_header_open '#' + #define f_fss_type_header_part1 ' ' + #define f_fss_type_header_part2 'f' + #define f_fss_type_header_part3 's' + #define f_fss_type_header_part4 's' + #define f_fss_type_header_part5 '-' + #define f_fss_type_header_close '\n' + + #define f_fss_id f_u_long + #define f_fss_checksum f_dynamic_string + #define f_fss_header_length f_string_length + + #define f_fss_id_initialize 0 + #define f_fss_checksum_initialize 0 + #define f_fss_header_length_initailize 0 +#endif // _di_f_fss_types_ + +#ifndef _di_f_fss_delimiters_ + #define f_fss_delimit_slash '\\' + #define f_fss_delimit_single_quote '\'' + #define f_fss_delimit_double_quote '"' + #define f_fss_delimit_placeholder f_placeholder +#endif //_di_f_fss_delimiters_ + +#ifndef _di_f_fss_codes_ +enum { + f_fss_basic, + f_fss_extended, + f_fss_basic_list, + f_fss_extended_list, + f_fss_very_basic_list, + f_fss_somewhat_basic_list, + f_fss_somewhat_extended_list, + f_fss_very_extended_list, + f_fss_embeded_list, + f_fss_reverse_mapping, + f_fss_extended_reverse_mapping, + f_fss_advanced_reverse_mapping, + f_fss_simple_list, +}; +#endif // _di_f_fss_codes_ + +#ifndef _di_f_fss_max_header_length_ + #define f_fss_max_header_length 12 +#endif // _di_f_fss_max_header_length_ + +#ifndef _di_f_fss_default_allocation_step_ + #define f_fss_default_allocation_step f_memory_default_allocation_step +#endif // _di_f_fss_default_allocation_step_ + +#ifndef _di_f_fss_delimits_ + typedef f_string_locations f_fss_delimits; + #define f_fss_delimits_initialize f_string_locations_initialize + + #define f_delete_fss_delimits(status, array) f_delete_string_location_array(status, array) + #define f_destroy_fss_delimits(status, array) f_destroy_string_location_array(status, array) + + #define f_resize_fss_delimits(status, array, new_length) f_resize_string_location_array(status, array, new_length) + #define f_adjust_fss_delimits(status, array, new_length) f_adjust_string_location_array(status, array, new_length) +#endif // _di_f_fss_delimits_ + +// stores information about a particular fss file, otherwise know as its header +#ifndef _di_f_fss_header_ + typedef struct { + f_fss_id type; // what kind of fss file is this? + f_fss_header_length length; // Total length of the header + } f_fss_header; + + #define f_fss_header_initialize { f_fss_id_initialize, f_fss_header_length_initialize } +#endif // _di_f_fss_header_ + +// This holds an array of fss_headers +#ifndef _di_f_fss_headers_ + typedef struct { + f_fss_header *array; // the array of fss headers + f_string_length size; // total amount of allocated space + f_string_length used; // total number of allocated spaces used + } f_fss_headers; + + #define f_fss_headers_initialize { 0, f_string_length_initialize, f_string_length_initialize } + + #define f_delete_fss_headers(status, headers) \ + f_delete_structure(status, headers, f_fss_header) + + #define f_destroy_fss_headers(status, headers) \ + f_destroy_structure(status, headers, f_fss_header) + + #define f_resize_fss_headers(status, headers, new_length) \ + f_resize_structure(status, headers, f_fss_header, new_length) + + + #define f_adjust_fss_headers(status, headers, new_length) \ + f_adjust_structure(status, headers, f_fss_header, new_length) +#endif // _di_f_fss_headers_ + + +// This is a location that represents an object +#ifndef _di_fss_object_ + typedef f_string_location f_fss_object; + #define f_fss_object_initialize f_string_location_initialize + + #define f_new_fss_object(status, object, length) status = f_new_array((void **) & object, sizeof(f_fss_object), length) + #define f_delete_fss_object(status, object) status = f_delete((void **) & object) + #define f_destroy_fss_object(status, object, size) status = f_destroy((void **) & object, sizeof(f_fss_object), size) + + #define f_resize_fss_object(status, object, old_length, new_length) \ + status = f_resize((void **) & object, sizeof(f_fss_object), old_length, new_length) + + #define f_adjust_fss_object(status, object, old_length, new_length) \ + status = f_adjust((void **) & object, sizeof(f_fss_object), old_length, new_length) +#endif // _di_fss_object_ + +// This holds an array of fss_object +#ifndef _di_fss_objects_ + typedef struct { + f_fss_object *array; // the array of fss objects + f_string_length size; // total amount of allocated space + f_string_length used; // total number of allocated spaces used + } f_fss_objects; + + #define f_fss_objects_initialize { 0, f_string_length_initialize, f_string_length_initialize } + + #define f_delete_fss_objects(status, objects) \ + f_delete_structure(status, objects, f_fss_object) + + #define f_destroy_fss_objects(status, objects) \ + f_destroy_structure(status, objects, f_fss_object) + + #define f_resize_fss_objects(status, objects, new_length) \ + f_resize_structure(status, objects, f_fss_object, new_length) + + #define f_adjust_fss_objects(status, objects, new_length) \ + f_destroy_structure(status, objects, f_fss_object, new_length) +#endif // _di_fss_objects_ + +// This holds an array of string locations that represent the content +// The very first string location will represent the outmost content +// All of the following string locations will represent the first level of nesting of all sub-content +// There will be no nesting beyond the first level recorded in this structure +#ifndef _di_fss_content_ + typedef struct { + f_string_location *array; // the array of locations + f_string_length size; // total amount of allocated space + f_string_length used; // total number of allocated spaces used + } f_fss_content; + + #define f_fss_content_initialize { 0, f_string_length_initialize, f_string_length_initialize } + + #define f_delete_fss_content(status, content) \ + f_delete_structure(status, content, f_string_location) + + #define f_destroy_fss_content(status, content) \ + f_destroy_structure(status, content, f_string_location) + + #define f_resize_fss_content(status, content, new_length) \ + f_resize_structure(status, content, f_string_location, new_length) + + #define f_adjust_fss_content(status, content, new_length) \ + f_adjust_structure(status, content, f_string_location, new_length) +#endif // _di_fss_content_ + +// This holds an array of fss_content +#ifndef _di_f_fss_contents_ + typedef struct { + f_fss_content *array; // the array of fss content + f_string_length size; // total amount of allocated space + f_string_length used; // total number of allocated spaces used + } f_fss_contents; + + #define f_fss_contents_initialize { 0, f_string_length_initialize, f_string_length_initialize } + + #define f_delete_fss_contents(status, contents) \ + f_delete_structures(status, contents, f_fss_content) + + #define f_destroy_fss_contents(status, contents) \ + f_destroy_structures(status, contents, f_fss_content) + + #define f_resize_fss_contents(status, contents, new_length) \ + f_resize_structures(status, contents, f_fss_content, new_length, f_string_length) + + #define f_adjust_fss_contents(status, contents, new_length) \ + f_resize_structures(status, contents, f_fss_content, new_length, f_string_length) +#endif // _di_f_fss_contents_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _F_fss_h diff --git a/level_0/f_memory/c/memory.c b/level_0/f_memory/c/memory.c new file mode 100644 index 0000000..45bf50a --- /dev/null +++ b/level_0/f_memory/c/memory.c @@ -0,0 +1,199 @@ +/* FLL - Level 0 + * Project: Memory + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Provide means to use memory routines, with error checking. + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_f_new_ + f_return_status f_new_array(void **pointer, const f_memory_size_t type, const f_memory_length length){ + #ifndef _di_level_0_parameter_checking_ + if (type <= 0) return f_invalid_parameter; + if (pointer == 0) return f_invalid_parameter; + #endif // _di_level_0_parameter_checking_ + + // prevent double-allocations + if (*pointer != 0) return f_none; + + // some people use malloc(type * length) to produce the same results + // I have noticed this sometimes causes an increase in L1/L2 cache misses (0.02% L1 increase, 0.01% L2 increase) + *pointer = calloc(type, length); + + if (*pointer){ + //memset(*pointer, 0, type * length); + return f_none; + } + + return f_allocation_error; + } +#endif // _di_f_new_ + +#ifndef _di_f_delete_ + f_return_status f_delete(void **pointer, const f_memory_size_t type, const f_memory_length length){ + #ifndef _di_level_0_parameter_checking_ + if (pointer == 0) return f_invalid_parameter; + #endif // _di_level_0_parameter_checking_ + + // prevent double-frees + if (*pointer == 0) return f_none; + + free(*pointer); + + // it has been deallocated, so reset the pointer + if (*pointer != 0) *pointer = 0; + + return f_none; + } +#endif // _di_f_delete_ + +#ifndef _di_f_destroy_ + f_return_status f_destroy(void **pointer, const f_memory_size_t type, const f_memory_length length){ + #ifndef _di_level_0_parameter_checking_ + if (length < 0) return f_invalid_parameter; + if (type <= 0) return f_invalid_parameter; + if (pointer == 0) return f_invalid_parameter; + #endif // _di_level_0_parameter_checking_ + + // prevent double-frees + if (*pointer == 0) return f_none; + + if (length > 0){ + memset(*pointer, 0, type * length); + } + + free(*pointer); + + // it has been deallocated, so reset the pointer + if (*pointer != 0) *pointer = 0; + + return f_none; + } +#endif // _di_f_destroy_ + +#ifndef _di_f_resize_ + f_return_status f_resize(void **pointer, const f_memory_size_t type, const f_memory_length old_length, const f_memory_length new_length){ + #ifndef _di_level_0_parameter_checking_ + if (type <= 0) return f_invalid_parameter; + if (old_length < 0) return f_invalid_parameter; + if (new_length < 0) return f_invalid_parameter; + if (pointer == 0) return f_invalid_parameter; + #endif // _di_level_0_parameter_checking_ + + // don't be wasteful + if (old_length == new_length) return f_none; + + if (*pointer != 0){ + void *new_pointer = 0; + + // allocate new space + if (new_length > 0){ + new_pointer = realloc(*pointer, type * new_length); + } else { + free(*pointer); + + // it has been deallocated, so reset the pointer + if (*pointer != 0) *pointer = 0; + + return f_none; + } + + if (new_pointer){ + if (new_pointer != *pointer){ + if (new_length > old_length){ + // bool * is of a data type size of 1, casting it to bool should result in a single-length increment + // this is done to avoid problems with (void *) having arithmetic issues + memset(((char *) new_pointer) + (type * old_length), 0, type * (new_length - old_length)); + } + + *pointer = new_pointer; + } + + return f_none; + } + } else if (new_length > 0){ + *pointer = calloc(type, new_length); + + if (*pointer){ + return f_none; + } + } else { + return f_none; + } + + return f_reallocation_error; + } +#endif // _di_f_resize_ + +#ifndef _di_f_adjust_ + f_return_status f_adjust(void **pointer, const f_memory_size_t type, const f_memory_length old_length, const f_memory_length new_length){ + #ifndef _di_level_0_parameter_checking_ + if (type <= 0) return f_invalid_parameter; + if (old_length < 0) return f_invalid_parameter; + if (new_length < 0) return f_invalid_parameter; + if (pointer == 0) return f_invalid_parameter; + #endif // _di_level_0_parameter_checking_ + + // don't be wasteful + if (old_length == new_length) return f_none; + + if (*pointer != 0){ + void *new_pointer = 0; + + if (old_length > 0){ + if (new_length < old_length){ + // bool * is of a data type size of 1, casting it to bool should result in a single-length increment + // this is done to avoid problems with (void *) having arithmetic issues + memset(((char *)*pointer) + new_length, 0, type * (old_length - new_length)); + } + } + + // allocate new space + if (new_length > 0){ + new_pointer = realloc(*pointer, type * new_length); + } else { + free(*pointer); + + // it has been deallocated, so reset the pointer + if (*pointer != 0) *pointer = 0; + + return f_none; + } + + if (new_pointer){ + if (new_pointer != *pointer){ + if (new_length > old_length){ + // char * is of a data type size of 1, casting it to bool should result in a single-length increment + // this is done to avoid problems with (void *) having arithmetic issues + memset(((char *)new_pointer) + (type * old_length), 0, type * (new_length - old_length)); + } + + *pointer = new_pointer; + } + + return f_none; + } + } else if (new_length > 0){ + *pointer = calloc(type, new_length); + + if (*pointer){ + return f_none; + } + } else { + return f_none; + } + + return f_reallocation_error; + } +#endif // _di_f_adjust_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_0/f_memory/c/memory.h b/level_0/f_memory/c/memory.h new file mode 100644 index 0000000..44cbebe --- /dev/null +++ b/level_0/f_memory/c/memory.h @@ -0,0 +1,245 @@ +/* FLL - Level 0 + * Project: Memory + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Provide means to use memory routines, with error checking. + * + * Possible error values on return: + * f_warn - a possible problem, but not an error (warning) + * f_critical - an error + * f_unknown - an unknown error + * f_invalid_parameter - a parameter sent to this function is invalid, error + * f_invalid_syntax - syntax for data sent to this is invalid, error + * f_invalid_data - something is wrong with the data sent to this function, error + * f_no_data - something is wrong with the data sent to this function, warning + * f_none - no errors or warnings + * f_allocation_error - an error during the allocation process + * f_reallocation_error - an error during the reallocation process + * f_deallocation_error - an error during the deallocation process + */ +#ifndef _F_memory_h +#define _F_memory_h + +// libc includes +#include +#include +#include +#include + +// fll includes +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifdef _f_memory_FORCE_secure_memory_ + #define _di_f_delete_ + #define f_delete(the_pointer, the_type, the_length) f_destroy(the_pointer, the_type, the_length) + + #define _di_f_resize_ + #define f_resize(the_pointer, the_type, the_old_length, the_new_length) f_adjust(the_pointer, the_type, the_old_length, the_new_length) + + #ifdef _f_memory_FORCE_fast_memory_ + #error You cannot define both _f_memory_FORCE_fast_memory_ and _f_memory_FORCE_secure_memory_ at the same time + #endif // _f_memory_FORCE_fast_memory_ +#endif // _f_memory_FORCE_secure_memory_ + +#ifdef _f_memory_FORCE_fast_memory_ + #define _di_f_destroy_ + #define f_destroy(the_pointer, the_type, the_length) f_delete(the_pointer, the_type, the_length) + + #define _di_f_adjust_ + #define f_adjust(the_pointer, the_type, the_old_length, the_new_length) f_resize(the_pointer, the_type, the_old_length, the_new_length) +#endif // _f_memory_FORCE_fast_memory_ + + +#ifndef _di_f_memory_default_allocation_step_ + // Everytime some array needs a single new element, reallocated by this amount + // Normally, this should be small, but when a large number of singular allocations are made, the overhead can be reduced by not having to reallocate space as often + // The problem then is that the more space allocated beyond what is initially needed will waste precious memory + // Change this if you know your application can afford to reduce the allocation overhead at the cost of more memory + #define f_memory_default_allocation_step 3 +#endif // _di_f_memory_default_allocation_step_ + +#ifndef _di_f_memory_types_ + #define f_memory_size_t f_size_t + #define f_memory_length f_size_t +#endif // _di_f_memory_types_ + +#ifndef _di_f_new_ + // Create some dynamically allocated array of some length + #define f_new(pointer,type) f_new_array(pointer, type, 1) + extern f_return_status f_new_array(void **pointer, const f_memory_size_t type, const f_memory_length length); +#endif // _di_f_new_ + +#ifndef _di_f_delete_ + // deletes some dynamically allocated data + // f_delete, will not change any of the data to 0 prior to deallocation + // type and length are not used by this function normally but must be provided for the cases when f_delete is swapped with f_destroy (or vice-versa) + extern f_return_status f_delete(void **pointer, const f_memory_size_t type, const f_memory_length length); +#endif // _di_f_delete_ + +#ifndef _di_f_destroy_ + // securely deletes some dynamically allocated data + // f_destroy, will change all data to 0 prior to deallocation + extern f_return_status f_destroy(void **pointer, const f_memory_size_t type, const f_memory_length length); +#endif // _di_f_destroy_ + +#ifndef _di_f_resize_ + // resizes some dynamically allocated data + // f_resize, will not change any of the data prior to deallocation + extern f_return_status f_resize(void **pointer, const f_memory_size_t type, const f_memory_length old_length, const f_memory_length new_length); +#endif // _di_f_resize_ + +#ifndef _di_f_adjust_ + // securely resizes some dynamically allocated data + // f_adjust, will change all data to 0 prior to deallocation + extern f_return_status f_adjust(void **pointer, const f_memory_size_t type, const f_memory_length old_length, const f_memory_length new_length); +#endif // _di_f_adjust_ + + +// the delete, destroy, resize, and adjust structure defines are mean to centralize allocation for all FLL structures that follow the size+used approach. +// improper use of these defines can lead to memory leaks and compilation errors +#ifndef _di_f_delete_structure_ + // status: the status to return + // structure: the structure to operate on + // type: the structure type + #define f_delete_structure(status, structure, type) \ + status = f_delete((void **) & structure.array, sizeof(type), structure.size); \ + if (status == f_none){ \ + structure.size = 0; \ + structure.used = 0; \ + } +#endif // _di_f_delete_structure_ + +#ifndef _di_f_destroy_structure_ + // status: the status to return + // structure: the structure to operate on + // type: the structure type + #define f_destroy_structure(status, structure, type) \ + status = f_destroy((void **) & structure.array, sizeof(type), structure.size); \ + if (status == f_none){ \ + structure.size = 0; \ + structure.used = 0; \ + } +#endif // _di_f_destroy_structure_ + +#ifndef _di_f_resize_structure_ + // status: the status to return + // structure: the structure to operate on + // type: the structure type + #define f_resize_structure(status, structure, type, new_length) \ + status = f_resize((void **) & structure.array, sizeof(type), structure.size, new_length); \ + if (status == f_none){ \ + structure.size = new_length; \ + if (structure.used > structure.size) structure.used = new_length; \ + } +#endif // _di_f_resize_structure_ + +#ifndef _di_f_adjust_structure_ + // status: the status to return + // structure: the structure to operate on + // type: the structure type + #define f_adjust_structure(status, structure, type, new_length) \ + status = f_adjust((void **) & structure.array, sizeof(type), structure.size, new_length); \ + if (status == f_none){ \ + structure.size = new_length; \ + if (structure.used > structure.size) structure.used = new_length; \ + } +#endif // _di_f_adjust_structure_ + +// the delete, destroy, resize, and adjust structures defines function in the same way that the delete, destroy, resize, and adjust structure defines do +// however, these hold an array of structure +// improper use of these defines can lead to memory leaks and compilation errors +#ifndef _di_f_delete_structures_ + // status: the status to return + // structures: the structure to operate on + // type: the structure type + #define f_delete_structures(status, structures, type) \ + status = f_none; \ + while (structures.size > 0){ \ + --structures.size; \ + f_delete_structure(status, structures.array[structures.size], type); \ + if (status != f_none) break; \ + } \ + if (status == f_none) status = f_delete((void **) & structures.array, sizeof(type), structures.size); \ + if (status == f_none) structures.used = f_string_length_initialize; +#endif // _di_f_delete_structures_ + +#ifndef _di_f_destroy_structures_ + // status: the status to return + // structures: the structure to operate on + // type: the structure type + #define f_destroy_structures(status, structures, type) \ + status = f_none; \ + while (structures.size > 0){ \ + --structures.size; \ + f_destroy_structure(status, structures.array[structures.size], type); \ + if (status != f_none) break; \ + } \ + if (status == f_none) status = f_destroy((void **) & structures.array, sizeof(type), structures.size); \ + if (status == f_none) structures.used = 0; +#endif // _di_f_destroy_structures_ + +#ifndef _di_f_resize_structures_ + // status: the status to return + // structures: the structure to operate on + // type: the structure type + #define f_resize_structures(status, structures, type, new_length, length_variable) \ + status = f_none; \ + if (new_length < structures.size){ \ + length_variable i = structures.size - new_length; \ + for (; i < structures.size; ++i){ \ + f_delete_structure(status, structures.array[i], type); \ + if (status != f_none) break; \ + } \ + } \ + if (status == f_none) status = f_resize((void **) & structures.array, sizeof(type), structures.size, new_length); \ + if (status == f_none) { \ + if (new_length > structures.size){ \ + length_variable i = structures.size; \ + for (; i < new_length; ++i){ \ + memset(&structures.array[i], 0, sizeof(type)); \ + } \ + } \ + structures.size = new_length; \ + if (structures.used > structures.size) structures.used = new_length; \ + } +#endif // _di_f_resize_structures_ + +#ifndef _di_f_adjust_structures_ + // status: the status to return + // structures: the structure to operate on + // type: the structure type + #define f_adjust_structures(status, structures, type, new_length, length_variable) \ + status = f_none; \ + if (new_length < structures.size){ \ + length_variable i = structures.size - new_length; \ + for (; i < structures.size; ++i){ \ + f_destroy_structure(status, structures.array[i], type); \ + if (status != f_none) break; \ + } \ + } \ + if (status == f_none) status = f_adjust((void **) & structures.array, sizeof(type), structures.size, new_length); \ + if (status == f_none) { \ + if (new_length > structures.size){ \ + length_variable i = structures.size; \ + for (; i < new_length; ++i){ \ + memset(&structures.array[i], 0, sizeof(type)); \ + } \ + } \ + structures.size = new_length; \ + if (structures.used > structures.size) structures.used = new_length; \ + } +#endif // _di_f_adjust_structures_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _F_memory_h diff --git a/level_0/f_output/c/output.c b/level_0/f_output/c/output.c new file mode 100644 index 0000000..a19fc38 --- /dev/null +++ b/level_0/f_output/c/output.c @@ -0,0 +1,69 @@ +/* FLL - Level 0 + * Project: Output + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_f_print_string_ + f_return_status f_print_string(f_file_type output, const f_string string, const f_string_length length){ + register f_string_length i = 0; + + for (; i < length; i++){ + if (string[i] != f_eos){ + if (fputc(string[i], output) == 0) return f_output_error; + } + } + + return f_none; + } +#endif // _di_f_print_string_ + +#ifndef _di_f_print_dynamic_string_ + f_return_status f_print_dynamic_string(f_file_type output, const f_dynamic_string buffer){ + #ifndef _di_level_0_parameter_checking_ + if (buffer.used <= 0) return f_invalid_parameter; + #endif // _di_level_0_parameter_checking_ + + register f_string_length i = 0; + + for (; i < buffer.used; i++){ + if (buffer.string[i] != f_eos){ + if (fputc(buffer.string[i], output) == 0) return f_output_error; + } + } + + return f_none; + } +#endif // _di_f_print_dynamic_string_ + +#ifndef _di_f_print_partial_dynamic_string_ + f_return_status f_print_partial_dynamic_string(f_file_type output, const f_dynamic_string buffer, const f_string_location location){ + #ifndef _di_level_0_parameter_checking_ + if (location.start < 0) return f_invalid_parameter; + if (location.stop < location.start) return f_invalid_parameter; + if (buffer.used <= 0) return f_invalid_parameter; + if (location.start >= buffer.used) return f_invalid_parameter; + if (location.stop >= buffer.used) return f_invalid_parameter; + #endif // _di_level_0_parameter_checking_ + + register f_string_length i = location.start; + + for (; i <= location.stop; i++){ + if (buffer.string[i] != f_eos){ + if (fputc(buffer.string[i], output) == 0) return f_output_error; + } + } + + return f_none; + } +#endif // _di_f_print_partial_dynamic_string_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_0/f_output/c/output.h b/level_0/f_output/c/output.h new file mode 100644 index 0000000..facf92c --- /dev/null +++ b/level_0/f_output/c/output.h @@ -0,0 +1,59 @@ +/* FLL - Level 0 + * Project: Output + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Provides some standard I/O functions not available in a libc + */ +#ifndef _F_output_h +#define _F_output_h + +// libc includes +#include +#include +#include +#include + +// fll-0 includes +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_f_print_string_ + // Similar to a c-library printf, except that this will only print a specific range + // will not stop at \0 + // will not print \0 + // This implementation will not proces special characters, such as %s in the same way as printf functions, I am undecided whether or not to add this capability + extern f_return_status f_print_string(f_file_type output, const f_string string, const f_string_length length); +#endif // _di_f_print_string_ + +#ifndef _di_f_print_dynamic_string_ + // Similar to a c-library printf, except that this will only print a specific range + // will not stop at \0 + // will not print \0 + // will print the entire dynamic string + // This implementation will not proces special characters, such as %s in the same way as printf functions, I am undecided whether or not to add this capability + extern f_return_status f_print_dynamic_string(f_file_type output, const f_dynamic_string buffer); +#endif // _di_f_print_dynamic_string_ + + +#ifndef _di_f_print_partial_dynamic_string_ + // Similar to a c-library printf, except that this will only print a specific range ( + // will not stop at \0 + // will not print \0 + // will print the only the buffer range specified by location + // This implementation will not proces special characters, such as %s in the same way as printf functions, I am undecided whether or not to add this capability + extern f_return_status f_print_partial_dynamic_string(f_file_type output, const f_dynamic_string buffer, const f_string_location location); +#endif // _di_f_print_partial_dynamic_string_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _F_output_h diff --git a/level_0/f_strings/c/strings.h b/level_0/f_strings/c/strings.h new file mode 100644 index 0000000..d626988 --- /dev/null +++ b/level_0/f_strings/c/strings.h @@ -0,0 +1,280 @@ +/* FLL - Level 0 + * Project: Strings + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Provides string capabilities + */ +#ifndef _F_strings_h +#define _F_strings_h + +// libc includes +#include + +// fll includes +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +// BUG: for whatever reason strnlen is considered not included with -Wall, even with __USE_GNU defined +// therefore this gets defined here +#ifndef _di_BUG_strnlen_ + extern size_t strnlen (const char *string, size_t max_length); +#endif // _di_BUG_strnlen_ + +// Define the end of string character +#ifndef _di_f_have_eos_ + #define f_eos '\0' +#endif // _di_f_have_eos_ + +// Define the end of line character +// FLL forbids '\r' and '\r\n' as end of line characters, \r will be silently ignored +#ifndef _di_f_have_eol_ + #define f_eol '\n' +#endif // _di_f_have_eol_ + +#ifndef _di_f_have_placeholder_ + #define f_placeholder '\0' +#endif // _di_f_have_placeholder_ + +// define the basic string type +#ifndef _di_f_have_string_ + typedef f_autochar *f_string; + + #define f_string_max_size f_unsigned_long_size + #define f_string_initialize f_eos + + #define f_new_string(status, string, length) status = f_new_array((void **) & string, sizeof(f_string), length) + #define f_delete_string(status, string, size) status = f_delete((void **) & string, sizeof(f_string), size) + #define f_destroy_string(status, string, size) status = f_destroy((void **) & string, sizeof(f_string), size) + + #define f_resize_string(status, string, old_length, new_length) \ + status = f_resize((void **) & string, sizeof(f_string), old_length, new_length) + + #define f_adjust_string(status, string, old_length, new_length) \ + status = f_adjust((void **) & string, sizeof(f_string), old_length, new_length) +#endif // _di_f_have_string_ + +#ifndef _di_string_format_pointers_ + #define string_format_string "%s" + #define string_format_character "%c" + #define string_format_integer "%i" + #define string_format_unsigned "%u" + #define string_format_double "%d" + #define string_format_float "%f" + #define string_format_long_integer "%li" + #define string_format_long_unsigned "%lu" + #define string_format_long_double "%ld" + #define string_format_long_float "%lf" + #define string_format_long_long_integer "%lli" + #define string_format_long_long_unsigned "%llu" + #define string_format_long_long_double "%lld" + #define string_format_long_long_float "%llf" +#endif // _di_string_format_pointers_ + +#ifndef _di_f_string_length_ + typedef f_u_long f_string_length; + + #define f_string_length_initialize 0 + + #define f_new_string_length(status, string, length) status = f_new_array((void **) & string, sizeof(f_string_length), length) + #define f_delete_string_length(status, string) status = f_delete((void **) & string) + #define f_destroy_string_length(status, string, size) status = f_destroy((void **) & string, sizeof(f_string_length), size) + + #define f_resize_string_length(status, length, old_length, new_length) \ + status = f_resize((void **) & length, sizeof(f_string_length), old_length, new_length) + + #define f_adjust_string_length(status, length, old_length, new_length) \ + status = f_adjust((void **) & length, sizeof(f_string_length), old_length, new_length) +#endif // _di_f_string_length_ + +#ifndef _di_f_string_lengths_ + typedef struct { + f_string_length *array; + f_string_length size; // total amount of allocated space + f_string_length used; // total number of allocated spaces used + } f_string_lengths; + + #define f_string_lengths_initialize { f_string_length_initialize, f_string_length_initialize, f_string_length_initialize } + + #define f_delete_string_lengths(status, lengths) \ + f_delete_structure(status, lengths, f_string_length) + + #define f_destroy_string_lengths(status, lengths) \ + f_destroy_structure(status, lengths, f_string_length) + + #define f_resize_string_lengths(status, lengths, new_length) \ + f_resize_structure(status, lengths, f_string_length, new_length) + + #define f_adjust_string_lengths(status, lengths, new_length) \ + f_adjust_structure(status, lengths, f_string_length, new_length) +#endif // _di_f_string_lengths_ + +// designates a start and stop position that represents a sub-string inside of some parent string +// use this to avoid resizing, restructuring, and reallocating the parent string to separate the sub-string +#ifndef _di_f_string_location_ + typedef struct { + f_string_length start; + f_string_length stop; + } f_string_location; + + #define f_string_location_initialize { f_string_length_initialize, f_string_length_initialize } + + #define f_new_string_location(status, string_location, length) status = f_new_array((void **) & string_location, sizeof(f_string_location), length) + #define f_delete_string_location(status, string_location, size) status = f_delete((void **) & string_location, sizeof(f_string_location), size) + #define f_destroy_string_location(status, string_location, size) status = f_destroy((void **) & string_location, sizeof(f_string_location), size) + + #define f_resize_string_location(status, string_location, old_length, new_length) \ + status = f_resize((void **) & string_location, sizeof(f_string_location), old_length, new_length) + + #define f_adjust_string_location(status, string_location, old_length, new_length) \ + status = f_adjust((void **) & string_location, sizeof(f_string_location), old_length, new_length) +#endif // _di_f_string_location_ + +// an array of string locations +#ifndef _di_f_string_locations_ + typedef struct { + f_string_location *array; // the array of string locations + f_string_length size; // total amount of allocated space + f_string_length used; // total number of allocated spaces used + } f_string_locations; + + #define f_string_locations_initialize {0, f_string_length_initialize, f_string_length_initialize} + + #define f_delete_string_locations(status, locations) \ + f_delete_structure(status, locations, f_string_location) + + #define f_destroy_string_locations(status, locations) \ + f_destroy_structure(status, locations, f_string_location) + + #define f_resize_string_locations(status, locations, new_length) \ + f_resize_structure(status, locations, f_string_location, new_length) + + #define f_adjust_string_locations(status, locations, new_length) \ + f_adjust_structure(status, locations, f_string_location, new_length) +#endif // _di_f_string_locations_ + +// a string that supports contains a size attribute to handle dynamic allocations and deallocations +// save the string size along with the string, so that strlen(..) commands can be avoided as much as possible +#ifndef _di_f_dynamic_string_ + typedef struct { + f_string string; // the string itself + f_string_length size; // total amount of allocated space + f_string_length used; // total number of allocated spaces used + } f_dynamic_string; + + #define f_dynamic_string_initialize { f_string_initialize, f_string_length_initialize, f_string_length_initialize } + + #define f_delete_dynamic_string(status, dynamic) \ + status = f_delete((void **) & dynamic.string, sizeof(f_string), dynamic.size); \ + if (status == f_none){ \ + dynamic.size = 0; \ + dynamic.used = 0; \ + } + + #define f_destroy_dynamic_string(status, dynamic) \ + status = f_destroy((void **) & dynamic.string, sizeof(f_string), dynamic.size); \ + if (status == f_none){ \ + dynamic.size = 0; \ + dynamic.used = 0; \ + } + + #define f_resize_dynamic_string(status, dynamic, new_length) \ + status = f_resize((void **) & dynamic.string, sizeof(f_string), dynamic.size, new_length); \ + if (status == f_none){ \ + dynamic.size = new_length; \ + if (dynamic.used > dynamic.size) dynamic.used = new_length; \ + } + + #define f_adjust_dynamic_string(status, dynamic, new_length) \ + status = f_adjust((void **) & dynamic.string, sizeof(f_string), dynamic.size, new_length); \ + if (status == f_none){ \ + dynamic.size = new_length; \ + if (dynamic.used > dynamic.size) dynamic.used = new_length; \ + } +#endif // _di_f_dynamic_string_ + +// an array of dynamic strings +#ifndef _di_f_dynamic_strings_ + typedef struct { + f_dynamic_string *array; // the array of dynamic strings + f_string_length size; // total amount of allocated space + f_string_length used; // total number of allocated spaces used + } f_dynamic_strings; + + #define f_dynamic_strings_initialize { 0, f_string_length_initialize, f_string_length_initialize } + + #define f_delete_dynamic_strings(status, dynamics) \ + status = f_none; \ + while (dynamics.size > 0){ \ + --dynamics.size; \ + f_delete_dynamic_string(status, dynamics.array[dynamics.size]); \ + if (status != f_none) break; \ + } \ + if (status == f_none) status = f_delete((void **) & dynamics.array, sizeof(f_dynamic_string), dynamics.size); \ + if (status == f_none) dynamics.used = 0; + + #define f_destroy_dynamic_strings(status, dynamics) \ + status = f_none; \ + while (dynamics.size > 0){ \ + --dynamics.size; \ + f_destroy_dynamic_string(status, dynamics.array[dynamics.size]); \ + if (status != f_none) break; \ + } \ + if (status == f_none) status = f_destroy((void **) & dynamics.array, sizeof(f_dynamic_string), dynamics.size); \ + if (status == f_none) dynamics.used = 0; + + #define f_resize_dynamic_strings(status, dynamics, new_length) \ + status = f_none; \ + if (new_length < dynamics.size){ \ + f_string_length i = dynamics.size - new_length; \ + for (; i < dynamics.size; ++i){ \ + f_delete_dynamic_string(status, dynamics.array[i]); \ + if (status != f_none) break; \ + } \ + } \ + if (status == f_none) status = f_resize((void **) & dynamics.array, sizeof(f_dynamic_string), dynamics.size, new_length); \ + if (status == f_none) { \ + if (new_length > dynamics.size){ \ + f_string_length i = dynamics.size; \ + for (; i < new_length; ++i){ \ + memset(&dynamics.array[i], 0, sizeof(f_string)); \ + } \ + } \ + dynamics.size = new_length; \ + if (dynamics.used > dynamics.size) dynamics.used = new_length; \ + } + + #define f_adjust_dynamic_strings(status, dynamics, new_length) \ + status = f_none; \ + if (new_length < dynamics.size){ \ + f_string_length i = dynamics.size - new_length; \ + for (; i < dynamics.size; ++i){ \ + f_destroy_dynamic_string(status, dynamics.array[i]); \ + if (status != f_none) break; \ + } \ + } \ + if (status == f_none) status = f_adjust((void **) & dynamics.array, sizeof(f_dynamic_string), dynamics.size, new_length); \ + if (status == f_none) { \ + if (new_length > dynamics.size){ \ + f_string_length i = dynamics.size; \ + for (; i < new_length; ++i){ \ + memset(&dynamics.array[i], 0, sizeof(f_dynamic_string)); \ + } \ + } \ + dynamics.size = new_length; \ + if (dynamics.used > dynamics.size) dynamics.used = new_length; \ + } +#endif // _di_f_dynamic_string_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _F_strings_h diff --git a/level_0/f_types/c/types.h b/level_0/f_types/c/types.h new file mode 100644 index 0000000..6e01287 --- /dev/null +++ b/level_0/f_types/c/types.h @@ -0,0 +1,146 @@ +/* FLL - Level 0 + * Project: Types + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Provides datatype re-definitions + * If your compiler lacks the ability to produce such, simply re-define them as needed + * An "ideal" definition for a standard expected size would be (64-bit): + * char: 2^16 = 65536 + * short: 2^32 = 4294967296 + * int: 2^64 = 1.84467e19 + * long: 2^128 = 3.40282e38 + * long long: 2^256 = 1.15792e77 + * + * TODO: Should a range type be implemented? (ie: f_range_short_long -> min=short, max=long) + */ +#ifndef _F_types_h +#define _F_types_h + +// libc includes +#include // contains mode_t, dev_t, gid_t, uid_t, etc.. +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_f_types_normal + #define f_s_int signed int + #define f_s_long signed long + #define f_s_short signed short + #define f_s_long_long signed long long + #define f_s_short_short signed short + #define f_s_double signed double + #define f_s_long_double signed long double + #define f_u_int unsigned int + #define f_u_short unsigned short + #define f_u_short_short unsigned short + #define f_u_long unsigned long + #define f_u_long_long unsigned long long + #define f_u_double unsigned double + #define f_u_long_double unsigned long double + #define f_char char // should ONLY be char + #define f_wchar wchar // should ONLY be wchar + #define f_autochar char // can be wchar or char + #define f_size_t size_t + #define f_bool unsigned short + #define f_mode_t mode_t + #define f_dev_t dev_t + #define f_uid_t uid_t + #define f_gid_t gid_t + #define f_ino_t ino_t + #define f_nlink_t nlink_t + #define f_off_t off_t + #define f_fpos_t fpos_t + #define f_file_type FILE * + #define f_null NULL +#endif // _di_f_types_normal + +// The minimal types represent to the system admin or whomever else handles compilation that the data type should NOT be smaller than the specified size, but can be any size larger. +// TODO: Should min_char be implemented? +#ifndef _di_f_types_min + #define f_min_s_int f_s_int + #define f_min_s_short f_s_short + #define f_min_s_long f_s_long + #define f_min_s_short_short f_s_short_short + #define f_min_s_long_long f_s_long_long + #define f_min_s_double f_s_double + #define f_min_s_long_double f_s_long_double + #define f_min_u_int f_u_int + #define f_min_u_short f_u_short + #define f_min_u_long f_u_long + #define f_min_u_short_short f_u_short_short + #define f_min_u_long_long f_u_long_long + #define f_min_u_double f_u_double + #define f_min_u_long_double f_u_long_double +#endif // _di_f_types_min + +// The maximum types represent to the system admin or whomever else handles compilation that the data type should NOT be larger than the specified size, but can be any size smaller. +// TODO: Should max_char be implemented? +#ifndef _di_f_types_max + #define f_max_s_int f_s_int + #define f_max_s_short f_s_short + #define f_max_s_long f_s_long + #define f_max_s_short_short f_s_short_short + #define f_max_s_long_long f_s_long_long + #define f_max_s_double f_s_double + #define f_max_s_long_double f_s_long_double + #define f_max_u_int f_u_int + #define f_max_u_short f_u_short + #define f_max_u_long f_u_long + #define f_max_u_short_short f_u_short_short + #define f_max_u_long_long f_u_long_long + #define f_max_u_double f_u_double + #define f_max_u_long_double f_u_long_double +#endif // _di_f_types_max + +#ifndef _di_f_status_ + typedef f_u_short f_status; + + #define f_status_initialize 0 + + // The c language gives warnings about return types of constants, I pretty much hate not being able to forcefully specify that these are not the be changed as that could be a security issue + // Therefore, I need to remove the const for c, but keep it for c++, thus I define the type f_return_status, which is only for function call declarations & prototypes + // DO NOT DECLARE THESE FOR THE RETURN DATA TYPES THEMSELVES, USE f_status. ONLY USE THESE FOR FUNCTION PROTOTYPES AND DECLARATIONS + #ifdef __cplusplus + #define f_return_status const f_status + #else + #define f_return_status f_status + #endif // __cplusplus +#endif // _di_f_status_ + +// Defines the maximum size to be supported +// I hope these don't get optimized away and are detected at runtime as a result of the bitwise operator +#ifndef _di_f_types_sizes_ + #define f_unsigned_char_size (~(unsigned char) 0) + #define f_unsigned_short_size (~(unsigned short) 0) + #define f_unsigned_int_size (~(unsigned int) 0) + #define f_unsigned_long_size (~(unsigned long) 0) + #define f_unsigned_long_long_size (~(unsigned long long) 0) + #define f_unsigned_double_size (~(unsigned double) 0) + #define f_unsigned_long_double_size (~(unsigned double) 0) + #define f_signed_char_size ((~(unsigned char) 0) / 2) + #define f_signed_short_size ((~(unsigned short) 0) / 2) + #define f_signed_int_size ((~(unsigned int) 0) / 2) + #define f_signed_long_size ((~(unsigned long) 0) / 2) + #define f_signed_long_long_size ((~(unsigned long long) 0) / 2) + #define f_signed_double_size ((~(unsigned double) 0) / 2) + #define f_signed_long_double_size ((~(unsigned double) 0) / 2) +#endif // _di_f_types_sizes_ + +// These should define some types use by stdio +#ifndef _di_f_types_standard_output_ + #define f_standard_input stdin + #define f_standard_output stdout + #define f_standard_error stderr + #define f_standard_warning stdout // I still hope for a separate pipe for warnings +#endif // _di_f_types_standard_output_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _F_types_h diff --git a/level_1/fl_colors/bash/colors.sh b/level_1/fl_colors/bash/colors.sh new file mode 100644 index 0000000..396e8dc --- /dev/null +++ b/level_1/fl_colors/bash/colors.sh @@ -0,0 +1,253 @@ +# FLL - Level 1 +# Project: Colors +# Version: 0.2.0 +# Licenses: flll, lgplv2.1 +# Programmers: Kevin Day +# Documentation: Provide basic color output support (linux & xterm) +# There will be future support for getting these values from a specified file, but at a higher level. + fl_color_none= + fl_color_reset="0" + fl_color_bold="1" + fl_color_underline="4" + fl_color_blink="5" + fl_color_highlight="7" + fl_color_nothing="8" + fl_color_black="30" + fl_color_red="31" + fl_color_green="32" + fl_color_yellow="33" + fl_color_blue="34" + fl_color_purple="35" + fl_color_teal="36" + fl_color_white="37" + fl_color_brightblack="90" + fl_color_brightred="91" + fl_color_brightgreen="92" + fl_color_brightyellow="93" + fl_color_brightblue="94" + fl_color_brightpurple="95" + fl_color_brightteal="96" + fl_color_brightwhite="97" + fl_color_black_bg="40" + fl_color_red_bg="41" + fl_color_green_bg="42" + fl_color_yellow_bg="43" + fl_color_blue_bg="44" + fl_color_purple_bg="45" + fl_color_teal_bg="46" + fl_color_white_bg="47" + fl_color_brightblack_bg="100" + fl_color_brightred_bg="101" + fl_color_brightgreen_bg="102" + fl_color_brightyellow_bg="103" + fl_color_brightblue_bg="104" + fl_color_brightpurple_bg="105" + fl_color_brightteal_bg="106" + fl_color_brightwhite_bg="107" + + # $1 = term, $2->$6 = colors, returned = color code returned + fl_set_color(){ + if [[ $1 == "lt" || $1 == "xt" ]] ; then + returned="\\033[" + local hit="no" + local fail="no" + local tailit="no" + + for i in $2 $3 $4 $5 $6 ; do + if [[ $1 == "xt" ]] ; then + case $i in + shade) + hit="yes" + tailit="no" + ;; + esac + elif [[ $1 == "lt" ]] ; then + case $i in + shade) + if [[ $tailit == "yes" ]] ; then returned="$returned;" ; fi + returned="$returned$fl_color_blink" + hit="yes" + tailit="yes" + ;; + blink) + hit="yes" + tailit="no" + ;; + nothing) + hit="yes" + tailit="no" + ;; + esac + fi + + if [[ $hit == "no" ]] ; then + + if [[ $tailit == "yes" ]] ; then + returned="$returned;" + tailit=no; + else + tailit=yes; + fi + + case $i in + reset) + returned="$returned$fl_color_reset" + tailit="yes" + ;; + bold) + returned="$returned$fl_color_bold" + tailit="yes" + ;; + underline) + returned="$returned$fl_color_underline" + tailit="yes" + ;; + blink) + returned="$returned$fl_color_blink" + tailit="yes" + ;; + highlight) + returned="$returned$fl_color_highlight" + tailit="yes" + ;; + nothing) + returned="$returned$fl_color_nothing" + tailit="yes" + ;; + black) + returned="$returned$fl_color_black" + tailit="yes" + ;; + red) + returned="$returned$fl_color_red" + tailit="yes" + ;; + green) + returned="$returned$fl_color_green" + tailit="yes" + ;; + yellow) + returned="$returned$fl_color_yellow" + tailit="yes" + ;; + blue) + returned="$returned$fl_color_blue" + tailit="yes" + ;; + purple) + returned="$returned$fl_color_purple" + tailit="yes" + ;; + teal) + returned="$returned$fl_color_teal" + tailit="yes" + ;; + white) + returned="$returned$fl_color_white" + tailit="yes" + ;; + brightblack) + returned="$returned$fl_color_brightblack" + tailit="yes" + ;; + brightred) + returned="$returned$fl_color_brightred" + tailit="yes" + ;; + brightgreen) + returned="$returned$fl_color_brightgreen" + tailit="yes" + ;; + brightyellow) + returned="$returned$fl_color_brightyellow" + tailit="yes" + ;; + brightblue) + returned="$returned$fl_color_brightblue" + tailit="yes" + ;; + brightpurple) + returned="$returned$fl_color_brightpurple" + tailit="yes" + ;; + brightteal) + returned="$returned$fl_color_brightteal" + tailit="yes" + ;; + brightwhite) + returned="$returned$fl_color_brightwhite" + tailit="yes" + ;; + black_bg) + returned="$returned$fl_color_black_bg" + tailit="yes" + ;; + red_bg) + returned="$returned$fl_color_red_bg" + tailit="yes" + ;; + green_bg) + returned="$returned$fl_color_green_bg" + tailit="yes" + ;; + yellow_bg) + returned="$returned$fl_color_yellow_bg" + tailit="yes" + ;; + blue_bg) + returned="$returned$fl_color_blue_bg" + tailit="yes" + ;; + purple_bg) + returned="$returned$fl_color_purple_bg" + tailit="yes" + ;; + teal_bg) + returned="$returned$fl_color_teal_bg" + tailit="yes" + ;; + white_bg) + returned="$returned$fl_color_white_bg" + tailit="yes" + ;; + brightblack_bg) + returned="$returned$fl_color_brightblack_bg" + tailit="yes" + ;; + brightred_bg) + returned="$returned$fl_color_brightred_bg" + tailit="yes" + ;; + brightgreen_bg) + returned="$returned$fl_color_brightgreen_bg" + tailit="yes" + ;; + brightyellow_bg) + returned="$returned$fl_color_brightyellow_bg" + tailit="yes" + ;; + brightblue_bg) + returned="$returned$fl_color_brightblue_bg" + tailit="yes" + ;; + brightpurple_bg) + returned="$returned$fl_color_brightpurple_bg" + tailit="yes" + ;; + brightteal_bg) + returned="$returned$fl_color_brightteal_bg" + tailit="yes" + ;; + brightwhite_bg) + returned="$returned$fl_color_brightwhite_bg" + tailit="yes" + ;; + esac + fi + + hit="no" + done + + returned="${returned}m" + fi + } diff --git a/level_1/fl_colors/c/colors.c b/level_1/fl_colors/c/colors.c new file mode 100644 index 0000000..ff199ea --- /dev/null +++ b/level_1/fl_colors/c/colors.c @@ -0,0 +1,187 @@ +/* FLL - Level 1 + * Project: Colors + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_set_color_ + f_return_status fl_set_color(f_file_type file, const f_colors_format format, const f_autochar *color1, const f_autochar *color2, const f_autochar *color3, const f_autochar *color4, const f_autochar *color5){ + #ifndef _di_level_1_parameter_checking_ + if (file == f_null) return f_invalid_parameter; + if (color1 == f_null) return f_invalid_parameter; + + // make sure all data is in the proper order + if (color2 == f_null && (color3 != f_null || color4 != f_null || color5 != f_null)) return f_invalid_parameter; + if (color3 == f_null && (color4 != f_null || color5 != f_null)) return f_invalid_parameter; + if (color4 == f_null && color5 != f_null) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + if (color2 == f_null) fprintf(file, "%s%s%s", format.begin, color1, format.end); + else if (color3 == f_null) fprintf(file, "%s%s%s%s%s", format.begin, color1, format.medium, color2, format.end); + else if (color4 == f_null) fprintf(file, "%s%s%s%s%s%s%s", format.begin, color1, format.medium, color2, format.medium, color3, format.end); + else if (color5 == f_null) fprintf(file, "%s%s%s%s%s%s%s%s%s", format.begin, color1, format.medium, color2, format.medium, color3, format.medium, color4, format.end); + else fprintf(file, "%s%s%s%s%s%s%s%s%s%s%s", format.begin, color1, format.medium, color2, format.medium, color3, format.medium, color4, format.medium, color5, format.end); + + return f_none; + } +#endif // _di_fl_set_color_ + +#ifndef _di_fl_save_color_ + f_return_status fl_save_color(f_dynamic_string *buffer, const f_colors_format format, const f_autochar *color1, const f_autochar *color2, const f_autochar *color3, const f_autochar *color4, const f_autochar *color5){ + #ifndef _di_level_1_parameter_checking_ + if (buffer == f_null) return f_invalid_parameter; + if (color1 == f_null) return f_invalid_parameter; + + // make sure all data is in the proper order + if (color2 == f_null && (color3 != f_null || color4 != f_null || color5 != f_null)) return f_invalid_parameter; + if (color3 == f_null && (color4 != f_null || color5 != f_null)) return f_invalid_parameter; + if (color4 == f_null && color5 != f_null) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + f_string_length string_size = strnlen(format.begin, f_color_max_size) + strnlen(format.end, f_color_max_size) + 1; + + if (color2 == f_null) string_size += strnlen(color1, f_color_max_size); + else if (color3 == f_null) string_size += strnlen(color1, f_color_max_size) + strnlen(color2, f_color_max_size); + else if (color4 == f_null) string_size += strnlen(color1, f_color_max_size) + strnlen(color2, f_color_max_size) + strnlen(color3, f_color_max_size); + else if (color5 == f_null) string_size += strnlen(color1, f_color_max_size) + strnlen(color2, f_color_max_size) + strnlen(color3, f_color_max_size) + strnlen(color4, f_color_max_size); + else string_size += strnlen(color1, f_color_max_size) + strnlen(color2, f_color_max_size) + strnlen(color3, f_color_max_size) + strnlen(color4, f_color_max_size) + strnlen(color5, f_color_max_size); + + // make sure there is enough allocated space, if not, then allocate some more + if (buffer->size - buffer->used - 1 < string_size){ + f_status status = f_status_initialize; + + f_resize_dynamic_string(status, (*buffer), buffer->used + string_size + 1); // the additional 1 is the EOS + + if (f_macro_test_for_allocation_errors(status)){ + return status; + } + } + + if (color2 == f_null){ + strncat(buffer->string, format.begin, f_color_max_size); + strncat(buffer->string, color1, f_color_max_size); + strncat(buffer->string, format.end, f_color_max_size); + } else if (color3 == f_null){ + strncat(buffer->string, format.begin, f_color_max_size); + strncat(buffer->string, color1, f_color_max_size); + strncat(buffer->string, format.medium, f_color_max_size); + strncat(buffer->string, color2, f_color_max_size); + strncat(buffer->string, format.end, f_color_max_size); + } else if (color4 == f_null){ + strncat(buffer->string, format.begin, f_color_max_size); + strncat(buffer->string, color1, f_color_max_size); + strncat(buffer->string, format.medium, f_color_max_size); + strncat(buffer->string, color2, f_color_max_size); + strncat(buffer->string, format.medium, f_color_max_size); + strncat(buffer->string, color3, f_color_max_size); + strncat(buffer->string, format.end, f_color_max_size); + } else if (color5 == f_null){ + strncat(buffer->string, format.begin, f_color_max_size); + strncat(buffer->string, color1, f_color_max_size); + strncat(buffer->string, format.medium, f_color_max_size); + strncat(buffer->string, color2, f_color_max_size); + strncat(buffer->string, format.medium, f_color_max_size); + strncat(buffer->string, color3, f_color_max_size); + strncat(buffer->string, format.medium, f_color_max_size); + strncat(buffer->string, color4, f_color_max_size); + strncat(buffer->string, format.end, f_color_max_size); + } else { + strncat(buffer->string, format.begin, f_color_max_size); + strncat(buffer->string, color1, f_color_max_size); + strncat(buffer->string, format.medium, f_color_max_size); + strncat(buffer->string, color2, f_color_max_size); + strncat(buffer->string, format.medium, f_color_max_size); + strncat(buffer->string, color3, f_color_max_size); + strncat(buffer->string, format.medium, f_color_max_size); + strncat(buffer->string, color4, f_color_max_size); + strncat(buffer->string, format.medium, f_color_max_size); + strncat(buffer->string, color5, f_color_max_size); + strncat(buffer->string, format.end, f_color_max_size); + } + + // update the amount of space that is to be used + buffer->used += string_size; + + // do not forget the EOS + buffer->string[buffer->used] = f_eos; + + return f_none; + } +#endif // _di_fl_save_color_ + +#ifndef _di_fl_print_color_ + f_return_status fl_print_color(f_file_type file, const f_dynamic_string start_color, const f_dynamic_string end_color, const f_autochar *string, ...){ + #ifndef _di_level_1_parameter_checking_ + if (file == f_null) return f_invalid_parameter; + if (string == f_null) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + if (start_color.used != 0){ + fprintf(file, "%s", start_color.string); + } + + va_list ap; + + va_start(ap, string); + + vfprintf(file, string, ap); + + va_end(ap); + + if (end_color.used != 0){ + fprintf(file, "%s", end_color.string); + } + + return f_none; + } +#endif // _di_fl_print_color_ + +#ifndef _di_fl_print_color_line_ + f_return_status fl_print_color_line(f_file_type file, const f_dynamic_string start_color, const f_dynamic_string end_color, const f_autochar *string, ...){ + #ifndef _di_level_1_parameter_checking_ + if (file == f_null) return f_invalid_parameter; + if (string == f_null) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + if (start_color.used != 0){ + fprintf(file, "%s", start_color.string); + } + + va_list ap; + + va_start(ap, string); + + vfprintf(file, string, ap); + + va_end(ap); + + if (end_color.used != 0){ + fprintf(file, "%s", end_color.string); + } + + // now print the trailing newline, this is done _after_ ending the colors to avoid color wrapping issues that can happen when a color code follows a newline + fprintf(file, "\n"); + + return f_none; + } +#endif // _di_fl_print_color_line_ + +#ifndef _di_fl_print_color_code_ + f_return_status fl_print_color_code(f_file_type file, const f_dynamic_string color){ + if (color.used != 0){ + fprintf(file, "%s", color.string); + } + + return f_none; + } +#endif // _di_fl_print_color_code_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_1/fl_colors/c/colors.h b/level_1/fl_colors/c/colors.h new file mode 100644 index 0000000..24cad50 --- /dev/null +++ b/level_1/fl_colors/c/colors.h @@ -0,0 +1,73 @@ +/* FLL - Level 1 + * Project: Colors + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Provide basic color output support (linux & xterm) + * This is the Featureless LINUX Library, so there is no support for non-linux colors at this time. + */ +#ifndef _FL_colors_h +#define _FL_colors_h + +// libc includes +#include +#include + +// fll-0 includes +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_set_color_ + // this will accept some file or standard io, and push color information to that file or standard io + extern f_return_status fl_set_color(f_file_type file, const f_colors_format format, const f_autochar *color1, const f_autochar *color2, const f_autochar *color3, const f_autochar *color4, const f_autochar *color5); + + #define fl_set_color1(file, format, color1) fl_set_color(file, format, color1, 0, 0, 0, 0) + #define fl_set_color2(file, format, color1, color2) fl_set_color(file, format, color1, color2, 0, 0, 0) + #define fl_set_color3(file, format, color1, color2, color3) fl_set_color(file, format, color1, color2, color3, 0, 0) + #define fl_set_color4(file, format, color1, color2, color3, color4) fl_set_color(file, format, color1, color2, color3, color4, 0) + #define fl_set_color5(file, format, color1, color2, color3, color4, color5) fl_set_color(file, format, color1, color2, color3, color4, color5) +#endif // _di_fl_set_color_ + + +#ifndef _di_fl_save_color_ + // this will place all appropriate color effects into a string, handling any necessary allocations + extern f_return_status fl_save_color(f_dynamic_string *buffer, const f_colors_format format, const f_autochar *color1, const f_autochar *color2, const f_autochar *color3, const f_autochar *color4, const f_autochar *color5); + + #define fl_save_color1(buffer, format, color1) fl_save_color(buffer, format, color1, 0, 0, 0, 0) + #define fl_save_color2(buffer, format, color1, color2) fl_save_color(buffer, format, color1, color2, 0, 0, 0) + #define fl_save_color3(buffer, format, color1, color2, color3) fl_save_color(buffer, format, color1, color2, color3, 0, 0) + #define fl_save_color4(buffer, format, color1, color2, color3, color4) fl_save_color(buffer, format, color1, color2, color3, color4, 0) + #define fl_save_color5(buffer, format, color1, color2, color3, color4, color5) fl_save_color(buffer, format, color1, color2, color3, color4, color5) +#endif // _di_fl_save_color_ + +#ifndef _di_fl_print_color_ + // this will wrap the passed text in the passed start and end colors + // this will work like fprintf with the variable arguments + // if the colors strings have nothing used in them, then this will only print the string + extern f_return_status fl_print_color(f_file_type file, const f_dynamic_string start_color, const f_dynamic_string end_color, const f_autochar *string, ...); +#endif // _di_fl_print_color_ + +#ifndef _di_fl_print_color_line_ + // this is identical to fl_print_color, but also prints a trailing newline + extern f_return_status fl_print_color_line(f_file_type file, const f_dynamic_string start_color, const f_dynamic_string end_color, const f_autochar *string, ...); +#endif // _di_fl_print_color_line_ + +#ifndef _di_fl_print_color_code_ + // this will print a single color code so that all print commands following this command will print in color (or not..) + // do not forget to print the color reset when done + extern f_return_status fl_print_color_code(f_file_type file, const f_dynamic_string color); +#endif // _di_fl_print_color_code_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FL_colors_h diff --git a/level_1/fl_console/c/console.c b/level_1/fl_console/c/console.c new file mode 100644 index 0000000..f11101c --- /dev/null +++ b/level_1/fl_console/c/console.c @@ -0,0 +1,226 @@ +/* FLL - Level 1 + * Project: Console + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_process_parameters_ + f_return_status fl_process_parameters(const f_u_int argc, const f_string argv[], f_console_parameter parameters[], const f_u_int total_parameters, f_string_lengths *remaining){ + #ifndef _di_level_1_parameter_checking_ + if (remaining == f_null) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + f_status status = f_status_initialize; + f_console_id result = 0; + f_bool found = f_false; + + f_u_int location = 1; // parameter 0 represents the program name so skip it + f_u_int sub_location = 0; + f_u_int increments = 0; + f_u_int string_length = 0; + f_u_int parameter_counter = 0; + + f_string_lengths extra_initiator = f_string_lengths_initialize; + + + // loop through and read all parameters + while (location < argc){ + f_console_identify(argv[location], &result); + + string_length = strnlen(argv[location], f_console_max_size); + + // process the current parameter + if (result == f_console_short_enable || result == f_console_short_disable) { + increments = 1; + sub_location = 1; + } else if (result == f_console_long_enable || result == f_console_long_disable) { + increments = string_length; + sub_location = 2; + } else if (result == f_console_extra_enable || result == f_console_extra_disable) { + increments = string_length; + sub_location = 3; + } else { + increments = 1; + sub_location = 0; + } + + // Now handle the normal commands + if (argv[location][0] == f_console_symbol_enable){ + while (sub_location < string_length){ + for (parameter_counter = 0; parameter_counter < total_parameters; parameter_counter++){ + if (parameters[parameter_counter].type == f_console_type_normal){ + if (parameters[parameter_counter].symbol_short != 0 && parameters[parameter_counter].symbol_long != 0){ + if (f_console_is_enable(result, &argv[location][sub_location], parameters[parameter_counter].symbol_short, parameters[parameter_counter].symbol_long, string_length + 1)){ + parameters[parameter_counter].result = f_console_result_found; + + if (parameters[parameter_counter].has_additional){ + if (extra_initiator.used >= extra_initiator.size){ + f_status allocation_status = f_status_initialize; + + f_resize_string_lengths(allocation_status, extra_initiator, extra_initiator.size + f_console_default_allocation_step); + if (f_macro_test_for_allocation_errors(allocation_status)){ + f_delete_string_lengths(status, extra_initiator); + return allocation_status; + } + } + + extra_initiator.array[extra_initiator.used] = parameter_counter; + extra_initiator.used++; + } + } + } + + if (parameters[parameter_counter].symbol_extra != 0) { + if (f_console_is_extra_enable(result, &argv[location][sub_location], parameters[parameter_counter].symbol_extra, string_length + 1)){ + parameters[parameter_counter].result = f_console_result_found; + + if (parameters[parameter_counter].has_additional){ + if (extra_initiator.used >= extra_initiator.size){ + f_status allocation_status = f_status_initialize; + + f_resize_string_lengths(allocation_status, extra_initiator, extra_initiator.size + f_console_default_allocation_step); + if (f_macro_test_for_allocation_errors(allocation_status)){ + f_delete_string_lengths(status, extra_initiator); + return allocation_status; + } + } + + extra_initiator.array[extra_initiator.used] = parameter_counter; + extra_initiator.used++; + } + } + } + } + } // for() + + sub_location += increments; + } // while() + + // now handle the inverse commands + } else if (argv[location][0] == f_console_symbol_disable) { + while (sub_location < string_length){ + for (parameter_counter = 0; parameter_counter < total_parameters; parameter_counter++){ + if (parameters[parameter_counter].type == f_console_type_inverse){ + if (parameters[parameter_counter].symbol_short != 0 && parameters[parameter_counter].symbol_long != 0){ + if (f_console_is_disable(result, &argv[location][sub_location], parameters[parameter_counter].symbol_short, parameters[parameter_counter].symbol_long, string_length + 1)){ + parameters[parameter_counter].result = f_console_result_found; + + if (parameters[parameter_counter].has_additional){ + if (extra_initiator.used >= extra_initiator.size){ + f_status allocation_status = f_status_initialize; + + f_resize_string_lengths(allocation_status, extra_initiator, extra_initiator.size + f_console_default_allocation_step); + if (f_macro_test_for_allocation_errors(allocation_status)){ + f_delete_string_lengths(status, extra_initiator); + return allocation_status; + } + } + + extra_initiator.array[extra_initiator.used] = parameter_counter; + extra_initiator.used++; + } + } + } + + if (parameters[parameter_counter].symbol_extra != 0) { + if (f_console_is_extra_disable(result, &argv[location][sub_location], parameters[parameter_counter].symbol_extra, string_length + 1)){ + parameters[parameter_counter].result = f_console_result_found; + + if (parameters[parameter_counter].has_additional){ + if (extra_initiator.used >= extra_initiator.size){ + f_status allocation_status = f_status_initialize; + + f_resize_string_lengths(allocation_status, extra_initiator, extra_initiator.size + f_console_default_allocation_step); + if (f_macro_test_for_allocation_errors(allocation_status)){ + f_delete_string_lengths(status, extra_initiator); + return allocation_status; + } + } + + extra_initiator.array[extra_initiator.used] = parameter_counter; + extra_initiator.used++; + } + } + } + } + } // for() + + sub_location += increments; + } // while() + } else { + // use found to determine if the remaining parameter should be populated + found = f_false; + + for (parameter_counter = 0; parameter_counter < total_parameters; parameter_counter++){ + if (parameters[parameter_counter].type == f_console_type_other){ + if (parameters[parameter_counter].length > 0 && parameters[parameter_counter].symbol_other != 0){ + if (strncmp(argv[location], parameters[parameter_counter].symbol_other, parameters[parameter_counter].length + 1) == 0){ + parameters[parameter_counter].result = f_console_result_found; + + // when "other" is supplied, the extra will be recycled to represent the location of the "other" such that ordering can be determined by the caller + parameters[parameter_counter].additional = location; + + found = f_true; + break; + } + } + } + } // for() + + if (!found){ + if (extra_initiator.used > 0){ + parameters[extra_initiator.array[0]].result = f_console_result_additional; + parameters[extra_initiator.array[0]].additional = location; + + extra_initiator.used--; + + f_string_length i = 0; + + for (; i < extra_initiator.used; i++){ + extra_initiator.array[i] = extra_initiator.array[i + 1]; + } + } else { + if (remaining->used >= remaining->size){ + f_status allocation_status = f_status_initialize; + + f_resize_string_lengths(allocation_status, (*remaining), remaining->size + f_console_default_allocation_step); + + if (f_macro_test_for_allocation_errors(allocation_status)){ + f_delete_string_lengths(status, extra_initiator); + return allocation_status; + } + } + + remaining->array[remaining->used] = location; + remaining->used++; + } + } + } + + ++location; + } // while() + + if (extra_initiator.used > 0){ + status = f_no_data; + } else { + status = f_none; + } + + { + f_status allocation_status = f_status_initialize; + f_delete_string_lengths(allocation_status, extra_initiator); + } + + return status; + } +#endif // _di_fl_process_parameters_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_1/fl_console/c/console.h b/level_1/fl_console/c/console.h new file mode 100644 index 0000000..abb7b44 --- /dev/null +++ b/level_1/fl_console/c/console.h @@ -0,0 +1,35 @@ +/* FLL - Level 1 + * Project: Console + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Some console input/output commands + */ +#ifndef _FL_console_h +#define _FL_console_h + +// libc include +#include + +// fll-0 includes +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_process_parameters_ + extern f_return_status fl_process_parameters(const f_u_int argc, const f_string argv[], f_console_parameter parameters[], const f_u_int total_parameters, f_string_lengths *remaining); +#endif // _di_fl_process_parameters_ + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FL_console_h diff --git a/level_1/fl_directory/c/directory.c b/level_1/fl_directory/c/directory.c new file mode 100644 index 0000000..f1dab13 --- /dev/null +++ b/level_1/fl_directory/c/directory.c @@ -0,0 +1,73 @@ +/* FLL - Level 1 + * Project: Directory + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_directory_list_ + // put the names of each file and/or directory inside the names parameter + f_return_status fl_directory_list(const f_string directory_path, f_dynamic_strings *names){ + #ifndef _di_level_1_parameter_checking_ + if (names == f_null) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + struct dirent **listing = 0; + f_s_int length = 0; + f_s_int counter = 0; + f_string_length size = f_string_length_initialize; + f_status status = f_status_initialize; + + length = scandir(directory_path, &listing, 0, alphasort); + + for (; counter < length; counter++) { + size = strnlen(listing[counter]->d_name, 256); // as far as I can tell 256 is the max directory name length + + // there is no reason to include "." and ".." in the directory listing + if (strncmp(listing[counter]->d_name, "..", 3) != 0 && strncmp(listing[counter]->d_name, ".", 2) != 0){ + if (names->used >= names->size){ + f_resize_dynamic_strings(status, (*names), names->used + fl_directory_default_allocation_step); + + if (f_macro_test_for_allocation_errors(status)){ + return status; + } + } + + f_resize_dynamic_string(status, names->array[names->used], size); + if (f_macro_test_for_allocation_errors(status)){ + return status; + } + + strncat(names->array[names->used].string, listing[counter]->d_name, size); + names->array[names->used].used = size; + names->used++; + } + + // FIXME: the second and third paramater are probably wrong + f_delete((void **) & listing[counter], sizeof(struct dirent), 0); + } + + // FIXME: the second and third paramater are probably wrong + f_delete((void **) & listing, sizeof(struct dirent *), 0); + + if (length == 0){ + // an empty directory + return f_no_data; + } else if (length == -1){ + if (errno == ENOMEM) return f_allocation_error; + else return f_failure; + } + + return f_none; + } +#endif // _di_fl_directory_list_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_1/fl_directory/c/directory.h b/level_1/fl_directory/c/directory.h new file mode 100644 index 0000000..7d51c38 --- /dev/null +++ b/level_1/fl_directory/c/directory.h @@ -0,0 +1,44 @@ +/* FLL - Level 1 + * Project: Directory + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Provides operations for directory handling + */ +#ifndef _FL_directory_h +#define _FL_directory_h + +// libc includes +#include +#include +#include +#include +#include +#include + +// fll-0 includes +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_directory_limitations_ + #define fl_directory_default_allocation_step f_memory_default_allocation_step +#endif // _di_fl_directory_limitations_ + +#ifndef _di_fl_directory_list_ + // put the names of each file and/or directory inside the names parameter + extern f_return_status fl_directory_list(const f_string directory_path, f_dynamic_strings *names); +#endif // _di_fl_directory_list_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FL_directory_h diff --git a/level_1/fl_execute/c/execute.c b/level_1/fl_execute/c/execute.c new file mode 100644 index 0000000..6d38043 --- /dev/null +++ b/level_1/fl_execute/c/execute.c @@ -0,0 +1,74 @@ +/* FLL - Level 1 + * Project: Execute + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Provides program execution operations similart to system() + * TODO: I should implement a function that will find the program based on PATH so that static paths do not have to be used + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_execute_path_ + f_return_status fl_execute_path(const f_string program_path, const f_dynamic_strings arguments, f_s_int *results){ + #ifndef _di_level_1_parameter_checking_ + if (results == f_null) return f_invalid_parameter; + + if (arguments.used <= 0) return f_invalid_parameter; + if (arguments.used > arguments.size) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + // create a string array that is compatible with execv() calls + f_status status = f_status_initialize; + f_autochar **arguments_array = 0; + + status = f_new_array((void **) & arguments_array, sizeof(f_autochar **), arguments.used + 1); + + if (f_macro_test_for_allocation_errors(status)) return status; + + { + f_string_length counter = f_string_length_initialize; + + for (; counter < arguments.used; counter++){ + arguments_array[counter] = arguments.array[counter].string; + } + + // insert the required array terminated + arguments_array[arguments.used] = 0; + } + + // TODO: validate that the file at program_path actually exists before attempting to fork and execute + f_s_int process_id = 0; + + process_id = vfork(); + + if (process_id < 0){ + return f_fork_failed; + } + + if (process_id == 0){ // child + execv(program_path, arguments_array); + + // according to manpages, calling _exit() is safer and should be called here instead of exit() + _exit(-1); + } + + // have the parent wait for the child process to finish + waitpid(process_id, results, 0); + + f_delete((void **) & arguments_array, sizeof(f_autochar), arguments.used + 1); + + if (*results != 0) return f_failure; + + return f_none; + } +#endif // _di_fl_execute_path_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_1/fl_execute/c/execute.h b/level_1/fl_execute/c/execute.h new file mode 100644 index 0000000..bea4b77 --- /dev/null +++ b/level_1/fl_execute/c/execute.h @@ -0,0 +1,42 @@ +/* FLL - Level 1 + * Project: Execute + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Provides program execution operations similar to system() + */ +#ifndef _FL_execute_h +#define _FL_execute_h + +// libc includes +#include +#include +#include + +// fll-0 includes +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_execute_path_ + // This will execute a program given some path + program name (such as "/bin/bash") + extern f_return_status fl_execute_path(const f_string program_path, const f_dynamic_strings arguments, f_s_int *results); +#endif // _di_fl_execute_path_ + +#ifndef _di_fl_execute_program_ + // TODO: this will find the program based on PATH environment so that static paths do not have to be used as with f_execute_path + //f_return_status fl_execute_program(const f_string program_name, const f_string arguments[], f_s_int *results); +#endif // _di_fl_execute_program_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FL_execute_h diff --git a/level_1/fl_file/c/file.c b/level_1/fl_file/c/file.c new file mode 100644 index 0000000..42831d0 --- /dev/null +++ b/level_1/fl_file/c/file.c @@ -0,0 +1,69 @@ +/* FLL - Level 1 + * Project: File + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_file_read_ + f_return_status fl_file_read(f_file file, const f_file_position position, f_dynamic_string *buffer){ + #ifndef _di_level_1_parameter_checking_ + if (buffer == f_null) return f_invalid_parameter; + + if (position.buffer_start < 0) return f_invalid_parameter; + if (position.file_start < 0) return f_invalid_parameter; + if (position.total_elements < 0) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + if (file.file == 0) return f_file_not_open; + + f_status status = f_status_initialize; + f_string_length size = f_string_length_initialize; + f_bool infinite = f_false; + + // when total_elements is 0, this means the file read will until EOF is reached + if (position.total_elements == 0){ + infinite = f_true; + size = f_file_default_read_size; + } else { + size = position.total_elements; + } + + // populate the buffer + do{ + f_resize_dynamic_string(status, (*buffer), size); + + if (f_macro_test_for_allocation_errors(status)){ + return status; + } + + status = f_file_read(&file, buffer, position); + + if (status == f_none_on_eof){ + break; + } else if (status != f_none){ + return status; + } + + if (infinite){ + if (size + f_file_default_read_size > f_string_max_size){ + return f_overflow; + } + + size += f_file_default_read_size; + } + } while (infinite); + + return f_none; + } +#endif // _di_fl_file_read_ + +#ifdef __cplusplus +} // extern "C" +#endif + diff --git a/level_1/fl_file/c/file.h b/level_1/fl_file/c/file.h new file mode 100644 index 0000000..a442ca4 --- /dev/null +++ b/level_1/fl_file/c/file.h @@ -0,0 +1,29 @@ +/* FLL - Level 1 + * Project: File + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * File Operations + */ +#ifndef _FL_file_h +#define _FL_file_h + +// fll-0 includes +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_file_read_ + extern f_return_status fl_file_read(f_file file, const f_file_position position, f_dynamic_string *buffer); +#endif // _di_fl_file_read_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FL_file_h diff --git a/level_1/fl_fss/c/fss.c b/level_1/fl_fss/c/fss.c new file mode 100644 index 0000000..6479260 --- /dev/null +++ b/level_1/fl_fss/c/fss.c @@ -0,0 +1,191 @@ +/* FLL - Level 1 + * Project: FSS + * Version: svn + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_fss_identify_ + f_return_status fl_fss_identify(const f_dynamic_string buffer, f_fss_header *header){ + #ifndef _di_level_1_parameter_checking_ + if (header == f_null) return f_invalid_parameter; + if (buffer.used <= 0) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + register f_string_length i = 0; + + // If this correctly follows the FSS specification, then this should be all that needs to be done (as well as atoh for ascii to hex) + if (buffer.string[i] == f_fss_type_header_open){ i++; + if (buffer.string[i] == f_fss_type_header_part1){ i++; + if (buffer.string[i] == f_fss_type_header_part2){ i++; + if (buffer.string[i] == f_fss_type_header_part3){ i++; + if (buffer.string[i] == f_fss_type_header_part4){ i++; + if (buffer.string[i] == f_fss_type_header_part5){ i++; + if (f_is_hexdigit(buffer.string[i]) == f_true){ i++; + if (f_is_hexdigit(buffer.string[i]) == f_true){ i++; + if (f_is_hexdigit(buffer.string[i]) == f_true){ i++; + if (f_is_hexdigit(buffer.string[i]) == f_true){ i++; + + f_string_location location = f_string_location_initialize; + + location.start = i - 4; + location.stop = i; + + // 1: A possibly valid header type was found, now convert it into its proper format and save the header type + f_string_to_hexdigit(buffer.string, &header->type, location); + + // 2: At this point, we can still know the proper format for the file and still have a invalid header, handle accordingly + if (buffer.string[i] == f_fss_type_header_close){ + i++; + header->length = i; + + return f_none; + } else { + // if "# fss-0000" is there, regardless of whats next, we can guess this to be of fss-0000, even if its fss-00001 (this is a guess afterall) + i++; + header->length = i; + + return fl_fss_accepted_but_invalid; + } + } + } + } + } + } + } + } + } + // people can miss spaces, so lets accept in an attempt to interpret the file anyway, but return values at this point are to be flagged as invalid + } else if (buffer.string[i] == f_fss_type_header_part2){ i++; + if (buffer.string[i] == f_fss_type_header_part3){ i++; + if (buffer.string[i] == f_fss_type_header_part4){ i++; + if (buffer.string[i] == f_fss_type_header_part5){ i++; + if (f_is_hexdigit(buffer.string[i]) == f_true){ i++; + if (f_is_hexdigit(buffer.string[i]) == f_true){ i++; + if (f_is_hexdigit(buffer.string[i]) == f_true){ i++; + if (f_is_hexdigit(buffer.string[i]) == f_true){ i++; + + f_string_location location = f_string_location_initialize; + + location.start = i - 4; + location.stop = i; + + f_string_to_hexdigit(buffer.string, &header->type, location); + + header->length = i + 1; + + return fl_fss_accepted_but_invalid; + } + } + } + } + } + } + } + } + } + + // TODO: At some point add checksum and compressions checks here, but the above statements will have to be adjusted accordingly + // 3: eventually this will be processing the checksum and 4: will be processing the compression + + return fl_fss_no_header; + } +#endif // _di_fl_fss_identify_ + +#ifndef _di_fl_fss_identify_file_ + f_return_status fl_fss_identify_file(f_file *file_information, f_fss_header *header){ + #ifndef _di_level_1_parameter_checking_ + if (file_information == f_null) return f_invalid_parameter; + if (header == f_null) return f_invalid_parameter; + if (file_information->file == 0) return f_file_not_open; + if (ferror(file_information->file) != 0) return f_file_error; + #endif // _di_level_1_parameter_checking_ + + clearerr(file_information->file); + + f_status status = f_status_initialize; + f_dynamic_string buffer = f_dynamic_string_initialize; + f_file_position location = f_file_position_initialize; + + // make sure we are in the proper location in the file + { + f_s_int seek_result = f_file_seek_from_beginning(file_information->file, 0); + + if (seek_result != 0) return f_file_seek_error; + } + + // 1: Prepare the buffer to handle a size of f_fss_max_header_length + location.total_elements = f_fss_max_header_length; + + f_adjust_dynamic_string(status, buffer, location.total_elements + 1); + + if (f_macro_test_for_allocation_errors(status)){ + return status; + } + + // 2: buffer the file + status = f_file_read(file_information, &buffer, location); + + if (f_macro_test_for_basic_errors(status) || f_macro_test_for_file_errors(status)){ + return status; + } + + // 3: Now attempt to process the file for the header + status = fl_fss_identify(buffer, header); + + return status; + } +#endif // _di_fl_fss_identify_file_ + +#ifndef _di_fl_fss_shift_delimiters_ +f_return_status fl_fss_shift_delimiters(f_dynamic_string *buffer, const f_string_location location){ + #ifndef _di_level_1_parameter_checking_ + if (buffer->used <= 0) return f_invalid_parameter; + if (location.start < 0) return f_invalid_parameter; + if (location.stop < location.start) return f_invalid_parameter; + if (location.start >= buffer->used) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + f_string_length position = f_string_length_initialize; + f_string_length distance = f_string_length_initialize; + + position = location.start; + + while (position < buffer->used && position <= location.stop){ + if (buffer->string[position] == f_fss_delimit_placeholder){ + distance++; + } + + // do not waste time trying to process what is only going to be replaced with a delimit placeholder + if (position + distance >= buffer->used || position + distance > location.stop){ + break; + } + + // shift everything down one for each placeholder found + if (distance > 0){ + buffer->string[position] = buffer->string[position + distance]; + } + + ++position; + } + + if (distance > 0){ + while (position < buffer->used + distance && position <= location.stop){ + buffer->string[position] = f_fss_delimit_placeholder; + ++position; + } + } + + return f_none; +} +#endif // _di_fl_fss_shift_delimiters_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_1/fl_fss/c/fss.h b/level_1/fl_fss/c/fss.h new file mode 100644 index 0000000..0ca7beb --- /dev/null +++ b/level_1/fl_fss/c/fss.h @@ -0,0 +1,48 @@ +/* FLL - Level 1 + * Project: FSS + * Version: svn + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#ifndef _FL_fss_h +#define _FL_fss_h + +// libc includes +#include +#include + +// fll-0 includes +#include +#include +#include +#include +#include +#include + +// fll-1 includes +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_fss_identify_ + extern f_return_status fl_fss_identify(const f_dynamic_string buffer, f_fss_header *header); +#endif // _di_fl_fss_identify_ + +#ifndef _di_fl_fss_identify_file_ + extern f_return_status fl_fss_identify_file(f_file *file_information, f_fss_header *header); +#endif // _di_fl_fss_identify_file_ + +#ifndef _di_fl_fss_shift_delimiters_ + // This provides a means to shift all of the delimiters to the end of the used buffer + // This allows one to do a printf on the dynamic string without the delimiters arbitrarily stopping the output + // No reallocations are performed, this will only shift characters + extern f_return_status fl_fss_shift_delimiters(f_dynamic_string *buffer, const f_string_location location); +#endif // _di_fl_fss_shift_delimiters_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FL_fss_h diff --git a/level_1/fl_fss/c/fss_basic.c b/level_1/fl_fss/c/fss_basic.c new file mode 100644 index 0000000..3c52381 --- /dev/null +++ b/level_1/fl_fss/c/fss_basic.c @@ -0,0 +1,306 @@ +/* FLL - Level 1 + * Project: FSS + * Version: svn + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_fss_basic_object_read_ + f_return_status fl_fss_basic_object_read(f_dynamic_string *buffer, f_string_location *input, f_fss_object *found){ + #ifndef _di_level_1_parameter_checking_ + if (buffer == f_null) return f_invalid_parameter; + if (input == f_null) return f_invalid_parameter; + if (found == f_null) return f_invalid_parameter; + if (input->start < 0) return f_invalid_parameter; + if (input->stop < input->start) return f_invalid_parameter; + if (buffer->used <= 0) return f_invalid_parameter; + if (input->start >= buffer->used) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + fl_macro_fss_skip_past_whitespace((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_error_on_eos, f_error_on_stop) + + // return found nothing if this line only contains whitespace and delimit placeholders + if (buffer->string[input->start] == f_fss_basic_close){ + input->start++; + return fl_fss_found_no_object; + } + + // when handling delimits, the only time they should be applied is when a valid object would exist + // however, the delimits will appear before a valid object, so remember their positions and only apply them after a would be valid object is confirmed + f_bool has_delimit = f_false; + f_bool ignore_quotes = f_false; + f_string_length location = f_string_length_initialize; + + // begin the search + found->start = input->start; + + // ignore all comment lines + if (buffer->string[input->start] == f_fss_comment){ + fl_macro_fss_object_seek_till_newline((*buffer), (*input), f_error_on_eos, f_error_on_stop) + + input->start++; + return fl_fss_found_no_object; + } + + // handle quote support + f_autochar quoted = f_eos; + + // identify where the object begins + if (buffer->string[input->start] == f_fss_delimit_slash){ + f_string_length first_slash = input->start; + input->start++; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + // A slash only delimits if a delimit quote would follow the slash (or a slash and a delimit quote follows) + if (buffer->string[input->start] == f_fss_delimit_single_quote || buffer->string[input->start] == f_fss_delimit_double_quote){ + location = first_slash; + has_delimit = f_true; + quoted = buffer->string[input->start]; + input->start++; + } else if (buffer->string[input->start] == f_fss_delimit_slash){ + do{ + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + if (buffer->string[input->start] == f_fss_delimit_single_quote || buffer->string[input->start] == f_fss_delimit_double_quote){ + location = first_slash; + has_delimit = f_true; + quoted = buffer->string[input->start]; + ignore_quotes = f_true; + input->start++; + } else if (!isgraph(buffer->string[input->start])) { + found->stop = input->start - 1; + input->start++; + return fl_fss_found_object; + } + } while (buffer->string[input->start] == f_fss_delimit_slash); + } + } else if (buffer->string[input->start] == f_fss_delimit_single_quote || buffer->string[input->start] == f_fss_delimit_double_quote){ + quoted = buffer->string[input->start]; + input->start++; + location = input->start; + } + + // identify where the object ends + if (quoted == f_eos){ + while (isgraph(buffer->string[input->start]) || buffer->string[input->start] == f_fss_delimit_placeholder){ + ++input->start; + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + } // while + + if (isspace(buffer->string[input->start])){ + found->stop = input->start - 1; + + if (buffer->string[input->start] == f_eol){ + input->start++; + return fl_fss_found_object_no_content; + } + + input->start++; + return fl_fss_found_object; + } + } else { + // remember the very first space in case a valid object close is not found + f_string_length pre_space = f_string_length_initialize; + f_bool found_space = f_false; + + // a dynamically populated location of all delimits to apply + f_string_lengths delimits = f_string_lengths_initialize; + + do{ + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + if (buffer->string[input->start] == f_eol){ + if (found_space){ + found->stop = pre_space; + input->start = pre_space; + } else { + found->stop = input->start - 1; + } + + input->start++; + + f_status status = f_status_initialize; + f_delete_string_lengths(status, delimits) + + if (found_space){ + return fl_fss_found_object; + } else { + return fl_fss_found_object_no_content; + } + } else if (isspace(buffer->string[input->start])) { + if (!found_space){ + pre_space = input->start - 1; + found_space = f_true; + } + } else if (buffer->string[input->start] == quoted) { + f_string_length quote_location = input->start; + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + if (isspace(buffer->string[input->start])) { + // this quote is a valid object close quote, so handle appropriately + if (has_delimit){ + buffer->string[location] = f_fss_delimit_placeholder; + + if (ignore_quotes){ + if (found_space){ + found->stop = pre_space; + input->start = pre_space; + } else { + found->stop = input->start -1; + } + } else { + found->stop = quote_location -1; + } + } else { + found->start = location; + found->stop = quote_location - 1; + } + + if (delimits.used > 0) { + f_string_length counter = 0; + + for (; counter < delimits.used; counter++) { + buffer->string[delimits.array[counter]] = f_fss_delimit_placeholder; + } // for + } + + f_status status = f_status_initialize; + f_delete_string_lengths(status, delimits) + + input->start++; + return fl_fss_found_object; + } else { + continue; + } + } else if (buffer->string[input->start] == f_fss_delimit_slash) { + f_string_length first_slash = input->start; + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + // A slash only delimits here if whitespace would follow the quote + if (buffer->string[input->start] == quoted){ + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + if (isspace(buffer->string[input->start])){ + if (delimits.used >= delimits.size){ + f_status status = f_status_initialize; + + f_resize_string_lengths(status, delimits, delimits.size + f_fss_default_allocation_step); + if (f_macro_test_for_allocation_errors(status)) return status; + } + + delimits.array[delimits.used] = first_slash; + delimits.used++; + } else { + continue; + } + } else if (buffer->string[input->start] == f_fss_delimit_slash) { + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + // A slash only delimits here if whitespace would follow the quote + if (buffer->string[input->start] == quoted){ + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + if (isspace(buffer->string[input->start])){ + if (delimits.used >= delimits.size){ + f_status status = f_status_initialize; + + f_resize_string_lengths(status, delimits, delimits.size + f_fss_default_allocation_step); + if (f_macro_test_for_allocation_errors(status)) return status; + } + + delimits.array[delimits.used] = first_slash; + delimits.used++; + } else { + continue; + } + } + } + } + + ++input->start; + } while (f_true); + } + + // seek to the end of the line + while (input->start < buffer->used && input->start <= input->stop && buffer->string[input->start] != f_eol) { + ++input->start; + } + + input->start++; + return fl_fss_found_no_object; + } +#endif // _di_fl_fss_basic_object_read_ + +#ifndef _di_fl_fss_basic_content_read_ + f_return_status fl_fss_basic_content_read(f_dynamic_string *buffer, f_string_location *input, f_fss_content *found) { + #ifndef _di_level_1_parameter_checking_ + if (buffer == f_null) return f_invalid_parameter; + if (input == f_null) return f_invalid_parameter; + if (found == f_null) return f_invalid_parameter; + if (input->start < 0) return f_invalid_parameter; + if (input->stop < input->start) return f_invalid_parameter; + if (buffer->used <= 0) return f_invalid_parameter; + if (input->start >= buffer->used) return f_invalid_parameter; + if (found->used > found->size) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + fl_macro_fss_skip_past_whitespace((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + // return found nothing if this line only contains whitespace and delimit placeholders + if (buffer->string[input->start] == f_eol){ + input->start++; + return fl_fss_found_no_content; + } + + fl_macro_fss_allocate_content_if_necessary((*found)); + found->array[found->used].start = input->start; + + // search for valid content + do{ + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + if (buffer->string[input->start] == f_fss_basic_close) break; + + ++input->start; + } while (f_true); + + // Save the stop point + found->array[found->used].stop = input->start - 1; + found->used++; + input->start++; + return fl_fss_found_content; + } +#endif // _di_fl_fss_basic_content_read_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_1/fl_fss/c/fss_basic.h b/level_1/fl_fss/c/fss_basic.h new file mode 100644 index 0000000..b7e7991 --- /dev/null +++ b/level_1/fl_fss/c/fss_basic.h @@ -0,0 +1,47 @@ +/* FLL - Level 1 + * Project: FSS + * Version: svn + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * This is the fss-0000 implementation + */ +#ifndef _FL_fss_basic_h +#define _FL_fss_basic_h + +// libc includes +#include +#include + +// fll-0 includes +#include +#include +#include +#include +#include + +// fll-1 includes +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_fss_basic_object_read_ + // read an fss-0000 object + extern f_return_status fl_fss_basic_object_read(f_dynamic_string *buffer, f_string_location *input, f_fss_object *found); +#endif // _di_fl_fss_basic_object_read_ + +#ifndef _di_fl_fss_basic_content_read_ + // read an fss-0000 content + extern f_return_status fl_fss_basic_content_read(f_dynamic_string *buffer, f_string_location *input, f_fss_content *found); +#endif // _di_fl_fss_basic_content_read_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FL_fss_basic_h diff --git a/level_1/fl_fss/c/fss_basic_list.c b/level_1/fl_fss/c/fss_basic_list.c new file mode 100644 index 0000000..f8288f9 --- /dev/null +++ b/level_1/fl_fss/c/fss_basic_list.c @@ -0,0 +1,558 @@ +/* FLL - Level 1 + * Project: FSS + * Version: svn + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_fss_basic_list_object_read_ + f_return_status fl_fss_basic_list_object_read(f_dynamic_string *buffer, f_string_location *input, f_fss_object *found){ + #ifndef _di_level_1_parameter_checking_ + if (buffer == f_null) return f_invalid_parameter; + if (input == f_null) return f_invalid_parameter; + if (found == f_null) return f_invalid_parameter; + if (input->start < 0) return f_invalid_parameter; + if (input->stop < input->start) return f_invalid_parameter; + if (buffer->used <= 0) return f_invalid_parameter; + if (input->start >= buffer->used) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + fl_macro_fss_skip_past_whitespace((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_error_on_eos, f_error_on_stop) + + // return found nothing if this line only contains whitespace and delimit placeholders + if (buffer->string[input->start] == f_eol){ + input->start++; + return fl_fss_found_no_object; + } else if (buffer->string[input->start] == f_fss_basic_list_open){ + fl_macro_fss_object_seek_till_newline((*buffer), (*input), f_error_on_eos, f_error_on_stop) + + input->start++; + return fl_fss_found_no_object; + } + + // when handling delimits, the only time they should be applied is when a valid object would exist + // however, the delimits will appear before a valid object, so remember their positions and only apply them after a would be valid object is confirmed + f_bool has_quote_delimit = f_false; + f_string_length quote_delimit = f_string_length_initialize; + + // begin the search + found->start = input->start; + + // ignore all comment lines + if (buffer->string[input->start] == f_fss_comment){ + fl_macro_fss_object_seek_till_newline((*buffer), (*input), f_error_on_eos, f_error_on_stop) + + input->start++; + return fl_fss_found_no_object; + } + + // handle quote support + f_autochar quoted = f_eos; + + // identify where the object begins + if (buffer->string[input->start] == f_fss_delimit_slash){ + f_string_length first_slash = input->start; + input->start++; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_error_on_eos, f_error_on_stop) + + // A slash only delimits if a delimit quote would follow the slash (or a slash and a delimit quote follows) + if (buffer->string[input->start] == f_fss_delimit_single_quote || buffer->string[input->start] == f_fss_delimit_double_quote){ + // because the slash properly delimited the quote, the quote then becomes the start of the content + found->start = first_slash + 1; + quote_delimit = first_slash; + has_quote_delimit = f_true; + } else if (buffer->string[input->start] == f_fss_delimit_slash){ + // only apply a slash delimit if the line begins with slashes followed by a quote + do { + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_error_on_eos, f_error_on_stop) + + if (buffer->string[input->start] == f_fss_delimit_single_quote || buffer->string[input->start] == f_fss_delimit_double_quote){ + found->start = first_slash + 1; + quote_delimit = first_slash; + has_quote_delimit = f_true; + break; + } else if (!isgraph(buffer->string[input->start])) { + fl_macro_fss_object_seek_till_newline((*buffer), (*input), f_error_on_eos, f_error_on_stop) + + input->start++; + return fl_fss_found_no_object; + } + } while (buffer->string[input->start] == f_fss_delimit_slash); + } + } else if (buffer->string[input->start] == f_fss_delimit_single_quote || buffer->string[input->start] == f_fss_delimit_double_quote){ + quoted = buffer->string[input->start]; + input->start++; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_unterminated_group_on_eos, f_unterminated_group_on_stop) + + found->start = input->start; + } else if (isgraph(buffer->string[input->start])) { + found->start = input->start; + } + + // identify where the object ends + if (quoted == f_eos){ + do{ + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_error_on_eos, f_error_on_stop) + + if (!isgraph(buffer->string[input->start])){ + break; + } else if (buffer->string[input->start] == f_fss_delimit_slash){ + f_string_length first_slash = input->start; + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_error_on_eos, f_error_on_stop) + + // A slash only delimits here if a basic list opener would follow the slash + if (buffer->string[input->start] == f_fss_basic_list_open){ + ++input->start; + + fl_macro_fss_skip_past_whitespace((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_error_on_eos, f_error_on_stop) + + // found a would be valid basic list object that has been delimited to not be a valid objecy, so exit + if (buffer->string[input->start] == f_fss_basic_list_close){ + input->start++; + return fl_fss_found_no_object; + } else { + // otherwise we now know this could never be a valid object so seek to the end of line and return without applying a delimit + fl_macro_fss_object_seek_till_newline((*buffer), (*input), f_error_on_eos, f_error_on_stop) + + input->start++; + return fl_fss_found_no_object; + } + } else if (buffer->string[input->start] == f_fss_delimit_slash){ + f_string_length second_slash = input->start; + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_error_on_eos, f_error_on_stop) + + if (buffer->string[input->start] == f_fss_basic_list_open){ + f_string_length open_position = input->start; + ++input->start; + + fl_macro_fss_skip_past_whitespace((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_error_on_eos, f_error_on_stop) + + // found a valid basic list object, so apply the delimit + if (buffer->string[input->start] == f_eol){ + if (has_quote_delimit){ + buffer->string[quote_delimit] = f_fss_delimit_placeholder; + } + + buffer->string[first_slash] = f_fss_delimit_placeholder; + found->stop = open_position - 1; + input->start++; + return fl_fss_found_object; + } + } else { + // return to the second slash, this way if there is a third or more, the quote test can be repeated + input->start = second_slash; + } + } + } else if (buffer->string[input->start] == f_fss_basic_list_open){ + f_string_length open_position = input->start; + input->start++; + + fl_macro_fss_skip_past_whitespace((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_error_on_eos, f_error_on_stop) + + // found a valid basic list object + if (buffer->string[input->start] == f_eol){ + if (has_quote_delimit){ + buffer->string[quote_delimit] = f_fss_delimit_placeholder; + } + + found->stop = open_position - 1; + input->start++; + return fl_fss_found_object; + } + } + + ++input->start; + } while (f_true); + } else { + f_string_length quote_location = f_string_length_initialize; + + // the quote must end before the opener begins, in this case the colon ':', so a quoted object would look like: "quoted object":\n + do{ + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_error_on_eos, f_error_on_stop) + + if (buffer->string[input->start] == f_eol){ + input->start++; + return fl_fss_found_no_object; + } + + // close quotes do not need to be delimited in this case as a valid quoted object must end with: ":\n + if (buffer->string[input->start] == quoted){ + // at this point, a valid object will need to be determined + // if nothing else is between the colon and the newline, then a valid object has been found + // otherwise restart the loop at this new position, looking for the next proper close quote + // This allows for an object name like the following to be valid: + // "My "Weird" Object": + // Whose object name is seen as: My "Weird" Object + quote_location = input->start; + input->start++; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_unterminated_group_on_eos, f_unterminated_group_on_stop) + + if (buffer->string[input->start] == f_fss_basic_list_open){ + input->start++; + + fl_macro_fss_skip_past_whitespace((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_error_on_eos, f_error_on_stop) + + if (buffer->string[input->start] == f_eol){ + found->stop = quote_location - 1; + input->start++; + return fl_fss_found_object; + } else { + continue; + } + } else { + continue; + } + } + + ++input->start; + } while (f_true); + } + + fl_macro_fss_object_seek_till_newline((*buffer), (*input), f_error_on_eos, f_error_on_stop) + + input->start++; + return fl_fss_found_no_object; + } +#endif // _di_fl_fss_basic_list_object_read_ + +#ifndef _di_fl_fss_basic_list_content_read_ + f_return_status fl_fss_basic_list_content_read(f_dynamic_string *buffer, f_string_location *input, f_fss_content *found){ + #ifndef _di_level_1_parameter_checking_ + if (buffer == f_null) return f_invalid_parameter; + if (input == f_null) return f_invalid_parameter; + if (found == f_null) return f_invalid_parameter; + if (input->start < 0) return f_invalid_parameter; + if (input->stop < input->start) return f_invalid_parameter; + if (buffer->used <= 0) return f_invalid_parameter; + if (input->start >= buffer->used) return f_invalid_parameter; + if (found->used > found->size) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + fl_macro_fss_allocate_content_if_necessary((*found)); + found->array[found->used].start = input->start; + + f_string_length last_newline = input->start; + f_bool has_newlines = f_false; + + // when handling delimits, the only time they should be applied is when a valid object would exist + // however, the delimits will appear before a valid object, so remember their positions and only apply them after a would be valid object is confirmed + f_bool has_quote_delimit = f_false; + f_string_length quote_delimit = f_string_length_initialize; + + // search until stop point, end of string, or until a valid basic list object is found + do{ + if (has_quote_delimit){ + has_quote_delimit = f_false; + } + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + if (buffer->string[input->start] == f_eol){ + has_newlines = f_true; + last_newline = input->start; + ++input->start; + continue; + } else if (buffer->string[input->start] == f_fss_basic_list_open){ + // a line that begins with only the basic list opener cannot be a valid list object so skip to next line + fl_macro_fss_content_seek_till_newline((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + has_newlines = f_true; + last_newline = input->start; + ++input->start; + continue; + } else if (buffer->string[input->start] == f_fss_comment){ + // comment lines are not valid objects so skip to next line + fl_macro_fss_content_seek_till_newline((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + has_newlines = f_true; + last_newline = input->start; + ++input->start; + continue; + } else { + // handle quote support + f_autochar quoted = f_eos; + + // identify where the object begins + if (buffer->string[input->start] == f_fss_delimit_slash){ + f_string_length first_slash = input->start; + input->start++; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + // A slash only delimits if a delimit quote would follow the slash (or a slash and a delimit quote follows) + if (buffer->string[input->start] == f_fss_delimit_single_quote || buffer->string[input->start] == f_fss_delimit_double_quote){ + // because the slash properly delimited the quote, the quote then becomes the start of the content + quote_delimit = first_slash; + has_quote_delimit = f_true; + } else if (buffer->string[input->start] == f_fss_delimit_slash){ + // only apply a slash delimit if the line begins with slashes followed by a quote + do { + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + if (buffer->string[input->start] == f_fss_delimit_single_quote || buffer->string[input->start] == f_fss_delimit_double_quote){ + quote_delimit = first_slash; + has_quote_delimit = f_true; + break; + } else if (!isgraph(buffer->string[input->start])) { + fl_macro_fss_content_seek_till_newline((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + break; + } + } while (buffer->string[input->start] == f_fss_delimit_slash); + + // if exited from above loop while at an EOL, then continue the main loop + if (buffer->string[input->start] == f_eol) { + continue; + } + } + } else if (buffer->string[input->start] == f_fss_delimit_single_quote || buffer->string[input->start] == f_fss_delimit_double_quote){ + quoted = buffer->string[input->start]; + input->start++; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_unterminated_group_on_eos, f_unterminated_group_on_stop) + } else if (!isgraph(buffer->string[input->start])) { + fl_macro_fss_content_seek_till_newline((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + continue; + } + + // identify where the potential object ends + if (quoted == f_eos){ + do{ + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + if (!isgraph(buffer->string[input->start])){ + while(buffer->string[input->start] != f_eol){ + ++input->start; + + if (input->start >= buffer->used){ + found->array[found->used].stop = input->stop; + found->used++; + return f_none_on_eos; + } + + if (input->start > input->stop){ + found->array[found->used].stop = input->stop; + found->used++; + return f_none_on_stop; + } + } // while + + has_newlines = f_true; + last_newline = input->start; + break; + } else if (buffer->string[input->start] == f_fss_delimit_slash){ + f_string_length first_slash = input->start; + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + // A slash only delimits here if a basic list opener would follow the slash + if (buffer->string[input->start] == f_fss_basic_list_open){ + f_string_length open_position = input->start; + ++input->start; + + fl_macro_fss_skip_past_whitespace((*buffer), (*input)) + + if (has_newlines){ + // In this case, assume a valid object was found when eos/eof was reached and reset the start position + fl_macro_fss_content_return_on_overflow_reset((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop, last_newline) + } else { + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + } + + // found a would be valid basic list object, so apply the delimit + if (buffer->string[input->start] == f_eol){ + buffer->string[first_slash] = f_fss_delimit_placeholder; + has_newlines = f_true; + last_newline = input->start; + break; + } else { + input->start = open_position; + ++input->start; + continue; + } + } else if (buffer->string[input->start] == f_fss_delimit_slash){ + f_string_length second_slash = input->start; + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + if (buffer->string[input->start] == f_fss_basic_list_open){ + f_string_length open_position = input->start; + ++input->start; + + fl_macro_fss_skip_past_whitespace((*buffer), (*input)) + + if (has_newlines){ + // In this case, assume a valid object was found when eos/eof was reached and reset the start position + fl_macro_fss_content_return_on_overflow_reset((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop, last_newline) + } else { + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + } + + // found a valid basic list object + if (buffer->string[input->start] == f_eol){ + // the content should not apply delimits for valid objects + if (has_newlines){ + input->start = last_newline; + found->array[found->used].stop = input->start - 1; + input->start++; + found->used++; + return fl_fss_found_content; + } + + // when there is no newline and an object was found, then no content was found because the starting line is the next object line! + input->start = last_newline; + return fl_fss_found_no_content; + } else { + input->start = open_position; + ++input->start; + continue; + } + } else { + // return to the second slash, this way if there is a third or more, the quote test can be repeated + input->start = second_slash; + ++input->start; + continue; + } + } + } else if (buffer->string[input->start] == f_fss_basic_list_open){ + f_string_length open_position = input->start; + input->start++; + + fl_macro_fss_skip_past_whitespace((*buffer), (*input)) + + if (has_newlines){ + // In this case, assume a valid object was found when eos/eof was reached and reset the start position + fl_macro_fss_content_return_on_overflow_reset((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop, last_newline) + } else { + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + } + + // found a valid basic list object + if (buffer->string[input->start] == f_eol){ + // the content should not apply delimits for valid objects + if (has_newlines){ + input->start = last_newline; + found->array[found->used].stop = input->start - 1; + input->start++; + found->used++; + return fl_fss_found_content; + } + + // when there is no newline and an object was found, then no content was found because the starting line is the next object line! + input->start = last_newline; + return fl_fss_found_no_content; + } else { + input->start = open_position; + } + } + + ++input->start; + } while (f_true); + } else { + // the quote must end before the opener begins, in this case the colon ':', so a quoted object would look like: "quoted object":\n + do{ + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_unterminated_group_on_eos, f_unterminated_group_on_stop) + + if (buffer->string[input->start] == f_eol){ + has_newlines = f_true; + last_newline = input->start; + break; + } + + // close quotes do not need to be delimited in this case as a valid quoted object must end with: ":\n + if (buffer->string[input->start] == quoted){ + // at this point, a valid object will need to be determined + // if nothing else is between the colon and the newline, then a valid object has been found + // otherwise restart the loop at this new position, looking for the next proper close quote + // This allows for an object name like the following to be valid: + // "My "Weird" Object": + // Whose object name is seen as: My "Weird" Object + input->start++; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_unterminated_group_on_eos, f_unterminated_group_on_stop) + + if (buffer->string[input->start] == f_fss_basic_list_open){ + input->start++; + + fl_macro_fss_skip_past_whitespace((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_error_on_eos, f_error_on_stop) + + if (buffer->string[input->start] == f_eol){ + if (has_newlines){ + input->start = last_newline; + found->array[found->used].stop = input->start - 1; + input->start++; + found->used++; + return fl_fss_found_content; + } + + // when there is no newline and an object was found, then no content was found because the starting line is the next object line! + input->start = last_newline; + return fl_fss_found_no_content; + } else { + continue; + } + } else { + continue; + } + } + + ++input->start; + } while (f_true); + } + } + + ++input->start; + } while (f_true); + + // should never get here + return f_unknown; + } +#endif // _di_fl_fss_basic_list_content_read_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_1/fl_fss/c/fss_basic_list.h b/level_1/fl_fss/c/fss_basic_list.h new file mode 100644 index 0000000..5cc8b11 --- /dev/null +++ b/level_1/fl_fss/c/fss_basic_list.h @@ -0,0 +1,48 @@ +/* FLL - Level 1 + * Project: FSS + * Version: svn + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * This is the fss-0002 implementation + */ +#ifndef _FL_fss_basic_list_h +#define _FL_fss_basic_list_h + +// libc includes +#include +#include + +// fll-0 includes +#include +#include +#include +#include +#include + +// fll-1 includes +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_fss_basic_list_object_read_ + // read an fss-0002 object + extern f_return_status fl_fss_basic_list_object_read(f_dynamic_string *buffer, f_string_location *input, f_fss_object *found); +#endif // _di_fl_fss_basic_list_object_read_ + +#ifndef _di_fl_fss_basic_list_content_read_ + // read an fss-0002 content + extern f_return_status fl_fss_basic_list_content_read(f_dynamic_string *buffer, f_string_location *input, f_fss_content *found); +#endif // _di_fl_fss_basic_list_content_read_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FL_fss_basic_list_h diff --git a/level_1/fl_fss/c/fss_errors.h b/level_1/fl_fss/c/fss_errors.h new file mode 100644 index 0000000..672c594 --- /dev/null +++ b/level_1/fl_fss/c/fss_errors.h @@ -0,0 +1,55 @@ +/* FLL - Level 1 + * Project: FSS + * Version: svn + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#ifndef _FL_fss_errors_h +#define _FL_fss_errors_h + +// fll-0 includes +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_macro_test_for_fss_errors_ + #define fl_macro_test_for_fss_errors(potential_error) \ + ( !f_macro_test_for_non_errors(potential_error) && \ + potential_error != fl_fss_no_header && \ + potential_error != fl_fss_no_header_eos && \ + potential_error != fl_fss_accepted_but_invalid && \ + potential_error != fl_fss_accepted_but_invalid_eos ) +#endif // _di_fl_macro_test_for_fss_errors_ + +enum { + fl_fss_error_start = f_last_error_code, + + #ifndef _di_fl_fss_errors_error_ + fl_fss_invalid_format, + fl_fss_invalid_format_eos, + #endif // _di_fl_fss_errors_error_ + + #ifndef _di_fl_fss_errors_warning_ + fl_fss_no_header, + fl_fss_accepted_but_invalid, + fl_fss_no_header_eos, + fl_fss_accepted_but_invalid_eos, + #endif // _di_fl_fss_errors_warning_ + + #ifndef _di_fl_fss_errors_success_ + fl_fss_found_object, + fl_fss_found_content, + fl_fss_found_no_object, + fl_fss_found_no_content, + fl_fss_found_object_no_content, // for the case where an object is found but no content could possibly exist + #endif // _di_fl_fss_errors_success_ +}; // enum + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FL_fss_errors_h diff --git a/level_1/fl_fss/c/fss_extended.c b/level_1/fl_fss/c/fss_extended.c new file mode 100644 index 0000000..4b50013 --- /dev/null +++ b/level_1/fl_fss/c/fss_extended.c @@ -0,0 +1,438 @@ +/* FLL - Level 1 + * Project: FSS + * Version: svn + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_fss_extended_object_read_ + f_return_status fl_fss_extended_object_read(f_dynamic_string *buffer, f_string_location *input, f_fss_object *found){ + #ifndef _di_level_1_parameter_checking_ + if (buffer == f_null) return f_invalid_parameter; + if (input == f_null) return f_invalid_parameter; + if (found == f_null) return f_invalid_parameter; + if (input->start < 0) return f_invalid_parameter; + if (input->stop < input->start) return f_invalid_parameter; + if (buffer->used <= 0) return f_invalid_parameter; + if (input->start >= buffer->used) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + fl_macro_fss_skip_past_whitespace((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_error_on_eos, f_error_on_stop) + + // return found nothing if this line only contains whitespace and delimit placeholders + if (buffer->string[input->start] == f_fss_extended_close){ + input->start++; + return fl_fss_found_no_object; + } + + // when handling delimits, the only time they should be applied is when a valid object would exist + // however, the delimits will appear before a valid object, so remember their positions and only apply them after a would be valid object is confirmed + f_bool has_delimit = f_false; + f_bool ignore_quotes = f_false; + f_string_length location = f_string_length_initialize; + + // begin the search + found->start = input->start; + + // ignore all comment lines + if (buffer->string[input->start] == f_fss_comment){ + fl_macro_fss_object_seek_till_newline((*buffer), (*input), f_error_on_eos, f_error_on_stop) + + input->start++; + return fl_fss_found_no_object; + } + + // handle quote support + f_autochar quoted = f_eos; + + // identify where the object begins + if (buffer->string[input->start] == f_fss_delimit_slash){ + f_string_length first_slash = input->start; + input->start++; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + // A slash only delimits if a delimit quote would follow the slash (or a slash and a delimit quote follows) + if (buffer->string[input->start] == f_fss_delimit_single_quote || buffer->string[input->start] == f_fss_delimit_double_quote){ + location = first_slash; + has_delimit = f_true; + quoted = buffer->string[input->start]; + input->start++; + } else if (buffer->string[input->start] == f_fss_delimit_slash){ + do{ + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + if (buffer->string[input->start] == f_fss_delimit_single_quote || buffer->string[input->start] == f_fss_delimit_double_quote){ + location = first_slash; + has_delimit = f_true; + quoted = buffer->string[input->start]; + ignore_quotes = f_true; + input->start++; + } else if (!isgraph(buffer->string[input->start])) { + found->stop = input->start - 1; + input->start++; + return fl_fss_found_object; + } + } while (buffer->string[input->start] == f_fss_delimit_slash); + } + } else if (buffer->string[input->start] == f_fss_delimit_single_quote || buffer->string[input->start] == f_fss_delimit_double_quote){ + quoted = buffer->string[input->start]; + input->start++; + location = input->start; + } + + // identify where the object ends + if (quoted == f_eos){ + while (isgraph(buffer->string[input->start]) || buffer->string[input->start] == f_fss_delimit_placeholder){ + ++input->start; + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + } // while + + if (isspace(buffer->string[input->start])){ + found->stop = input->start - 1; + + if (buffer->string[input->start] == f_eol){ + input->start++; + return fl_fss_found_object_no_content; + } + + input->start++; + return fl_fss_found_object; + } + } else { + // remember the very first space in case a valid object close is not found + f_string_length pre_space = f_string_length_initialize; + f_bool found_space = f_false; + + // a dynamically populated location of all delimits to apply + f_string_lengths delimits = f_string_lengths_initialize; + + do{ + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + if (buffer->string[input->start] == f_eol){ + if (found_space){ + found->stop = pre_space; + input->start = pre_space; + } else { + found->stop = input->start - 1; + } + + input->start++; + + f_status status = f_status_initialize; + f_delete_string_lengths(status, delimits) + + if (found_space){ + return fl_fss_found_object; + } else { + return fl_fss_found_object_no_content; + } + } else if (isspace(buffer->string[input->start])) { + if (!found_space){ + pre_space = input->start - 1; + found_space = f_true; + } + } else if (buffer->string[input->start] == quoted) { + f_string_length quote_location = input->start; + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + if (isspace(buffer->string[input->start])) { + // this quote is a valid object close quote, so handle appropriately + if (has_delimit){ + buffer->string[location] = f_fss_delimit_placeholder; + + if (ignore_quotes){ + if (found_space){ + found->stop = pre_space; + input->start = pre_space; + } else { + found->stop = input->start -1; + } + } else { + found->stop = quote_location -1; + } + } else { + found->start = location; + found->stop = quote_location - 1; + } + + if (delimits.used > 0) { + f_string_length counter = 0; + + for (; counter < delimits.used; counter++) { + buffer->string[delimits.array[counter]] = f_fss_delimit_placeholder; + } // for + } + + f_status status = f_status_initialize; + f_delete_string_lengths(status, delimits) + + input->start++; + return fl_fss_found_object; + } else { + continue; + } + } else if (buffer->string[input->start] == f_fss_delimit_slash) { + f_string_length first_slash = input->start; + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + // A slash only delimits here if whitespace would follow the quote + if (buffer->string[input->start] == quoted){ + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + if (isspace(buffer->string[input->start])){ + if (delimits.used >= delimits.size){ + f_status status = f_status_initialize; + + f_resize_string_lengths(status, delimits, delimits.size + f_fss_default_allocation_step); + if (f_macro_test_for_allocation_errors(status)) return status; + } + + delimits.array[delimits.used] = first_slash; + delimits.used++; + } else { + continue; + } + } else if (buffer->string[input->start] == f_fss_delimit_slash) { + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + // A slash only delimits here if whitespace would follow the quote + if (buffer->string[input->start] == quoted){ + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_object_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + if (isspace(buffer->string[input->start])){ + if (delimits.used >= delimits.size){ + f_status status = f_status_initialize; + + f_resize_string_lengths(status, delimits, delimits.size + f_fss_default_allocation_step); + if (f_macro_test_for_allocation_errors(status)) return status; + } + + delimits.array[delimits.used] = first_slash; + delimits.used++; + } else { + continue; + } + } + } + } + + ++input->start; + } while (f_true); + } + + // seek to the end of the line + while(input->start < buffer->used && input->start <= input->stop && buffer->string[input->start] != f_eol){ + ++input->start; + } + + input->start++; + return fl_fss_found_no_object; + } +#endif // _di_fl_fss_extended_object_read_ + +#ifndef _di_fl_fss_extended_content_read_ + f_return_status fl_fss_extended_content_read(f_dynamic_string *buffer, f_string_location *input, f_fss_content *found){ + #ifndef _di_level_1_parameter_checking_ + if (buffer == f_null) return f_invalid_parameter; + if (input == f_null) return f_invalid_parameter; + if (found == f_null) return f_invalid_parameter; + if (input->start < 0) return f_invalid_parameter; + if (input->stop < input->start) return f_invalid_parameter; + if (buffer->used <= 0) return f_invalid_parameter; + if (input->start >= buffer->used) return f_invalid_parameter; + if (found->used > found->size) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + f_autochar quoted = f_eos; + f_string_length original = found->used; + + fl_macro_fss_allocate_content_if_necessary((*found)) + found->array[found->used].start = input->start; + + while (input->start <= input->stop){ + // get past all leading spaces/tabs (allowed) + fl_macro_fss_skip_past_whitespace((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + if (buffer->string[input->start] == f_eol){ + break; + } + + fl_macro_fss_allocate_content_if_necessary((*found)) + found->array[found->used].start = input->start; + + // this inner loop should read until whitespace is found then mark the end of a specific content field + do{ + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + // handle delimited quotes, single quotes, and double quotes + if (buffer->string[input->start] == f_fss_delimit_slash){ + do{ + f_string_length first_slash = input->start; + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + // A slash only delimits if a delimit quote would follow the slash (or a slash and a delimit quote follows) + if (buffer->string[input->start] == f_fss_delimit_single_quote || buffer->string[input->start] == f_fss_delimit_double_quote){ + // because the slash properly delimited the quote, the quote then becomes the start of the content + found->array[found->used].start = input->start; + buffer->string[first_slash] = f_fss_delimit_placeholder; + break; + } else if (buffer->string[input->start] == f_fss_delimit_slash){ + f_string_length second_slash = input->start; + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + if (buffer->string[input->start] == f_fss_delimit_single_quote || buffer->string[input->start] == f_fss_delimit_double_quote){ + buffer->string[first_slash] = f_fss_delimit_placeholder; + + quoted = buffer->string[input->start]; + input->start++; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_unterminated_group_on_eos, f_unterminated_group_on_stop) + + found->array[found->used].start = input->start; + break; + } else { + // return to the second slash, this way if there is a third or more, the quote test can be repeated + input->start = second_slash; + ++input->start; + } + } else { + break; + } + } while (f_true); + } else if (buffer->string[input->start] == f_fss_delimit_single_quote || buffer->string[input->start] == f_fss_delimit_double_quote){ + quoted = buffer->string[input->start]; + input->start++; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_unterminated_group_on_eos, f_unterminated_group_on_stop) + + found->array[found->used].start = input->start; + } + + // when quoted is null, then spaces will end the content, otherwise the quote defined in quoted will end the content (or a newline) + if (quoted == f_eos){ + do{ + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + if (buffer->string[input->start] == f_fss_extended_close){ + // Save the stop point + found->array[found->used].stop = input->start - 1; + found->used++; + input->start++; + return fl_fss_found_content; + } + + if (isspace(buffer->string[input->start])) break; + + ++input->start; + } while (f_true); + } else { + do{ + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + if (buffer->string[input->start] == f_fss_extended_close){ + input->start++; + return f_unterminated_group; + } + + // handle delimited quotes + if (buffer->string[input->start] == f_fss_delimit_slash){ + f_string_length first_slash = input->start; + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_none_on_eos, f_none_on_stop) + + // A slash only delimits if a delimit quote would follow the slash (or a slash and a delimit quote follows) + if (buffer->string[input->start] == quoted){ + buffer->string[first_slash] = f_fss_delimit_placeholder; + ++input->start; + continue; + } else if (buffer->string[input->start] == f_fss_delimit_slash){ + f_string_length second_slash = input->start; + ++input->start; + + fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*input)) + fl_macro_fss_content_return_on_overflow((*buffer), (*input), (*found), f_unterminated_group_on_eos, f_unterminated_group_on_stop) + + if (buffer->string[input->start] == quoted){ + buffer->string[first_slash] = f_fss_delimit_placeholder; + quoted = f_eos; + break; + } else { + // return to the second slash, this way if there is a third or more, the quote test can be repeated + input->start = second_slash; + ++input->start; + continue; + } + } + } else if (buffer->string[input->start] == quoted){ + quoted = f_eos; + break; + } + + ++input->start; + } while (f_true); + } + + // Save the stop point + found->array[found->used].stop = input->start - 1; + found->used++; + break; + } while (f_true); + + ++input->start; + } + + // When original is the same as the current found->used, then there was no data found + if (original == found->used){ + input->start++; + return fl_fss_found_no_content; + } + + return fl_fss_found_content; + } +#endif // _di_fl_fss_extended_content_read_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_1/fl_fss/c/fss_extended.h b/level_1/fl_fss/c/fss_extended.h new file mode 100644 index 0000000..65a9c99 --- /dev/null +++ b/level_1/fl_fss/c/fss_extended.h @@ -0,0 +1,48 @@ +/* FLL - Level 1 + * Project: FSS + * Version: svn + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * This is the fss-0001 implementation + */ +#ifndef _FL_fss_extended_h +#define _FL_fss_extended_h + +// libc includes +#include +#include + +// fll-0 includes +#include +#include +#include +#include +#include + +// fll-1 includes +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_fss_extended_object_read_ + // read an fss-0001 object + extern f_return_status fl_fss_extended_object_read(f_dynamic_string *buffer, f_string_location *input, f_fss_object *found); +#endif // _di_fl_fss_extended_object_read_ + +#ifndef _di_fl_fss_extended_content_read_ + // read an fss-0001 content + extern f_return_status fl_fss_extended_content_read(f_dynamic_string *buffer, f_string_location *input, f_fss_content *found); +#endif // _di_fl_fss_extended_content_read_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FL_fss_extended_h diff --git a/level_1/fl_fss/c/fss_macro.h b/level_1/fl_fss/c/fss_macro.h new file mode 100644 index 0000000..22bbf8c --- /dev/null +++ b/level_1/fl_fss/c/fss_macro.h @@ -0,0 +1,116 @@ +/* FLL - Level 1 + * Project: FSS + * Version: svn + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Provides generic functionality shared between and used by different fss processing functions + */ +#ifndef _FL_fss_macro_h +#define _FL_fss_macro_h + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_macro_fss_skip_past_whitespace_ + #define fl_macro_fss_skip_past_whitespace(buffer, input) \ + while (!isgraph(buffer.string[input.start]) || buffer.string[input.start] == f_fss_delimit_placeholder){ \ + if (buffer.string[input.start] == f_eol) break; \ + \ + ++input.start;\ + \ + if (input.start >= buffer.used) break; \ + if (input.start > input.stop) break; \ + } // while +#endif // _di_fl_macro_fss_skip_past_whitespace_ + +#ifndef _di_fl_macro_fss_skip_past_delimit_placeholders_ + #define fl_macro_fss_skip_past_delimit_placeholders(buffer, input) \ + while (buffer.string[input.start] == f_fss_delimit_placeholder){ \ + ++input.start;\ + \ + if (input.start >= buffer.used) break; \ + if (input.start > input.stop) break; \ + } // while +#endif // _di_fl_macro_fss_skip_past_delimit_placeholders_ + +#ifndef _di_fl_macro_fss_object_return_on_overflow_ + #define fl_macro_fss_object_return_on_overflow(buffer, input, found, eos_status, stop_status) \ + if (input.start >= buffer.used){ \ + found.stop = buffer.used - 1; \ + return eos_status; \ + } else if (input.start > input.stop){ \ + found.stop = input.stop; \ + return stop_status; \ + } +#endif // _di_fl_macro_fss_object_return_on_overflow_ + +#ifndef _di_fl_macro_fss_content_return_on_overflow_ + #define fl_macro_fss_content_return_on_overflow(buffer, input, found, eos_status, stop_status) \ + if (input.start >= buffer.used){ \ + found.array[found.used].stop = buffer.used - 1; \ + return eos_status; \ + } else if (input.start > input.stop){ \ + found.array[found.used].stop = input.stop; \ + return stop_status; \ + } +#endif // _di_fl_macro_fss_content_return_on_overflow_ + +#ifndef _di_fl_macro_fss_content_return_on_overflow_reset_ + #define fl_macro_fss_content_return_on_overflow_reset(buffer, input, found, eos_status, stop_status, set_stop) \ + if (input.start >= buffer.used){ \ + input.start = set_stop; \ + found.array[found.used].stop = set_stop; \ + return eos_status; \ + } else if (input.start > input.stop){ \ + input.start = set_stop; \ + found.array[found.used].stop = set_stop; \ + return stop_status; \ + } +#endif // _di_fl_macro_fss_content_return_on_overflow_reset_ + +#ifndef _di_fl_macro_fss_allocate_content_if_necessary_ + #define fl_macro_fss_allocate_content_if_necessary(content) \ + if (content.used >= content.size){ \ + f_status status = f_status_initialize; \ + \ + f_resize_fss_content(status, content, content.size + f_fss_default_allocation_step); \ + if (f_macro_test_for_allocation_errors(status)) return status; \ + } +#endif // _di_fl_macro_fss_allocate_content_if_necessary_ + +#ifndef _di_fl_macro_fss_object_seek_till_newline_ + #define fl_macro_fss_object_seek_till_newline(buffer, input, eos_status, stop_status) \ + while(buffer.string[input.start] != f_eol){ \ + ++input.start; \ + if (input.start >= buffer.used){ \ + return eos_status; \ + } \ + if (input.start > input.stop){ \ + return stop_status; \ + } \ + } // while +#endif // _di_fl_macro_fss_object_seek_till_newline_ + +#ifndef _di_fl_macro_fss_content_seek_till_newline_ + #define fl_macro_fss_content_seek_till_newline(buffer, input, found, eos_status, stop_status) \ + while(buffer.string[input.start] != f_eol){ \ + ++input.start; \ + if (input.start >= buffer.used){ \ + found.array[found.used].stop = input.stop; \ + return eos_status; \ + } \ + if (input.start > input.stop){ \ + found.array[found.used].stop = input.stop; \ + return stop_status; \ + } \ + } // while +#endif // _di_fl_macro_fss_content_seek_till_newline_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FL_fss_macro_h diff --git a/level_1/fl_strings/c/strings.c b/level_1/fl_strings/c/strings.c new file mode 100644 index 0000000..2c85d13 --- /dev/null +++ b/level_1/fl_strings/c/strings.c @@ -0,0 +1,228 @@ +/* FLL - Level 1 + * Project: Strings + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_rip_string_ + f_return_status fl_rip_string(const f_dynamic_string buffer, const f_string_location position, f_dynamic_string *results){ + #ifndef _di_level_1_parameter_checking_ + if (results == f_null) return f_invalid_parameter; + if (position.start < 0) return f_invalid_parameter; + if (position.stop < position.start) return f_invalid_parameter; + if (buffer.used <= 0) return f_invalid_parameter; + if (position.start >= buffer.used) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + // the start and stop point are inclusive locations, and therefore start - stop is actually 1 too few locations + f_string_length size = position.stop - position.start + 1; + + if (size > 0){ + f_status status = f_status_initialize; + + f_resize_dynamic_string(status, (*results), size); + + if (f_macro_test_for_allocation_errors(status)){ + return status; + } + + memcpy(results->string, buffer.string + position.start, sizeof(f_autochar) * size); + results->used = size; + + return f_none; + } + + return f_no_data; + } +#endif // _di_fl_rip_string_ + +#ifndef _di_fl_seek_line_past_non_graph_ + f_return_status fl_seek_line_past_non_graph(const f_dynamic_string buffer, f_string_location *position, const f_autochar placeholder){ + #ifndef _di_level_1_parameter_checking_ + if (position == f_null) return f_invalid_parameter; + if (position->start < 0) return f_invalid_parameter; + if (position->stop < position->start) return f_invalid_parameter; + if (buffer.used <= 0) return f_invalid_parameter; + if (position->start >= buffer.used) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + while (!isgraph(buffer.string[position->start]) || buffer.string[position->start] == placeholder){ + if (buffer.string[position->start] == f_eol) return f_none; + + ++position->start; + + if (position->start >= buffer.used) return f_none_on_eos; + if (position->start > position->stop) return f_none_on_stop; + } // while() + + return f_none; + } +#endif // _di_fl_seek_line_past_non_graph_ + +#ifndef _di_fl_seek_line_until_non_graph_ + f_return_status fl_seek_line_until_non_graph(const f_dynamic_string buffer, f_string_location *position, const f_autochar placeholder){ + #ifndef _di_level_1_parameter_checking_ + if (position->start < 0) return f_invalid_parameter; + if (position->stop < position->start) return f_invalid_parameter; + if (buffer.used <= 0) return f_invalid_parameter; + if (position->start >= buffer.used) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + while (isgraph(buffer.string[position->start]) || buffer.string[position->start] == placeholder){ + if (buffer.string[position->start] == f_eol) return f_none; + + ++position->start; + + if (position->start >= buffer.used) return f_none_on_eos; + if (position->start > position->stop) return f_none_on_stop; + } // while() + + return f_none; + } +#endif // _di_fl_seek_line_until_non_graph_ + +#ifndef _di_fl_seek_to_ + f_return_status fl_seek_to(const f_dynamic_string buffer, f_string_location *position, const f_autochar seek_to_this){ + #ifndef _di_level_1_parameter_checking_ + if (position->start < 0) return f_invalid_parameter; + if (position->stop < position->start) return f_invalid_parameter; + if (buffer.used <= 0) return f_invalid_parameter; + if (position->start >= buffer.used) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + while (buffer.string[position->start] != seek_to_this){ + if (buffer.string[position->start] == f_eol) return f_none; + + ++position->start; + + if (position->start >= buffer.used) return f_none_on_eos; + if (position->start > position->stop) return f_none_on_stop; + } // while() + + return f_none; + } +#endif // _di_fl_seek_to_ + +#ifndef _di_fl_compare_strings_ + f_return_status fl_compare_strings(const f_string string1, const f_string string2, const f_string_length length1, const f_string_length length2){ + #ifndef _di_level_1_parameter_checking_ + if (length1 <= 0) return f_invalid_parameter; + if (length2 <= 0) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + f_string_length i1 = f_string_length_initialize; + f_string_length i2 = f_string_length_initialize; + + f_string_length stop1 = length1; + f_string_length stop2 = length2; + + for (; i1 < stop1 && i2 < stop2; i1++, i2++){ + while (i1 < stop1 && string1[i1] == f_eos) i1++; + while (i2 < stop2 && string2[i2] == f_eos) i2++; + + if (string1[i1] != string2[i2]) return f_not_equal_to; + } // for() + + while (i1 < stop1){ + if (string1[i1] != f_eos) return f_not_equal_to; + i1++; + } // while() + + while (i2 < stop2){ + if (string2[i2] != f_eos) return f_not_equal_to; + i2++; + } // while() + + return f_equal_to; + } +#endif // _di_fl_compare_strings_ + +#ifndef _di_fl_compare_dynamic_strings_ + f_return_status fl_compare_dynamic_strings(const f_dynamic_string string1, const f_dynamic_string string2){ + #ifndef _di_level_1_parameter_checking_ + if (string1.used <= 0) return f_invalid_parameter; + if (string2.used <= 0) return f_invalid_parameter; + + if (string1.used > string1.size) return f_invalid_parameter; + if (string2.used > string2.size) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + f_string_length i1 = f_string_length_initialize; + f_string_length i2 = f_string_length_initialize; + + f_string_length stop1 = string1.used; + f_string_length stop2 = string2.used; + + for (; i1 < stop1 && i2 < stop2; i1++, i2++){ + while (i1 < stop1 && string1.string[i1] == f_eos) i1++; + while (i2 < stop2 && string2.string[i2] == f_eos) i2++; + + if (string1.string[i1] != string2.string[i2]) return f_not_equal_to; + } // for() + + while (i1 < stop1){ + if (string1.string[i1] != f_eos) return f_not_equal_to; + i1++; + } // while() + + while (i2 < stop2){ + if (string2.string[i2] != f_eos) return f_not_equal_to; + i2++; + } // while() + + return f_equal_to; + } +#endif // _di_fl_compare_dynamic_strings_ + +#ifndef _di_fl_compare_partial_dynamic_strings_ + f_return_status fl_compare_partial_dynamic_strings(const f_dynamic_string string1, const f_dynamic_string string2, const f_string_location offset1, const f_string_location offset2){ + #ifndef _di_level_1_parameter_checking_ + if (string1.used <= 0) return f_invalid_parameter; + if (string2.used <= 0) return f_invalid_parameter; + + if (string1.used > string1.size) return f_invalid_parameter; + if (string2.used > string2.size) return f_invalid_parameter; + + if (offset1.start > offset1.stop) return f_invalid_parameter; + if (offset2.start > offset2.stop) return f_invalid_parameter; + + if (string1.used <= offset1.stop) return f_invalid_parameter; + if (string2.used <= offset2.stop) return f_invalid_parameter; + #endif // _di_level_1_parameter_checking_ + + f_string_length i1 = offset1.start; + f_string_length i2 = offset2.start; + + f_string_length stop1 = offset1.stop + 1; + f_string_length stop2 = offset2.stop + 1; + + for (; i1 < stop1 && i2 < stop2; i1++, i2++){ + while (i1 < stop1 && string1.string[i1] == f_eos) i1++; + while (i2 < stop2 && string2.string[i2] == f_eos) i2++; + + if (string1.string[i1] != string2.string[i2]) return f_not_equal_to; + } // for() + + while (i1 < stop1){ + if (string1.string[i1] != f_eos) return f_not_equal_to; + i1++; + } // while() + + while (i2 < stop2){ + if (string2.string[i2] != f_eos) return f_not_equal_to; + i2++; + } // while() + + return f_equal_to; + } +#endif // _di_fl_compare_partial_dynamic_strings_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_1/fl_strings/c/strings.h b/level_1/fl_strings/c/strings.h new file mode 100644 index 0000000..3610e58 --- /dev/null +++ b/level_1/fl_strings/c/strings.h @@ -0,0 +1,74 @@ +/* FLL - Level 1 + * Project: Strings + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Provides basic string manipulation and processing capabilities + */ +#ifndef _FL_strings_h +#define _FL_strings_h + +// libc includes +#include +#include + +// fll includes +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fl_rip_string_ + // given a start and stop position, this will return a new string based from the supplied buffer, based on the passed positions + // this will replace/overwrite existing information inside of the results variable + extern f_return_status fl_rip_string(const f_dynamic_string buffer, const f_string_location position, f_dynamic_string *results); +#endif // _di_fl_rip_string_ + +#ifndef _di_fl_seek_line_past_non_graph_ + // given a dynamic string and a string location, seek past all non-graph characters until a graph is reached + // will ignore the given placeholder + extern f_return_status fl_seek_line_past_non_graph(const f_dynamic_string buffer, f_string_location *position, const f_autochar placeholder); +#endif // _di_fl_seek_line_past_non_graph_ + +#ifndef _di_fl_seek_line_until_non_graph_ + // given a dynamic string and a string location, seek past all graph characters until a non-graph is reached + // will ignore the given placeholder + extern f_return_status fl_seek_line_until_non_graph(const f_dynamic_string buffer, f_string_location *position, const f_autochar placeholder); +#endif // _di_fl_seek_line_until_non_graph_ + +#ifndef _di_fl_seek_to_ + // given a dynamic string and a string location, seek past all characters until the given character is reached + extern f_return_status fl_seek_to(const f_dynamic_string buffer, f_string_location *position, const f_autochar seek_to_this); +#endif // _di_fl_seek_to_ + +#ifndef _di_fl_compare_strings_ + // this compares two strings and works similar to that of strncmp(..) but has significant differences to strncmp(..) + // given two strings, this will return either f_equal_to or f_not_equal_to + // this does not stop on f_eos and f_eos will be ignored as if it were not taking up any space, therefor a 5 character string could return f_equal_to if the 5 character string contains an f_eos anywhere within it + extern f_return_status fl_compare_strings(const f_string string1, const f_string string2, const f_string_length length1, const f_string_length length2); +#endif // _di_fl_compare_strings_ + +#ifndef _di_fl_compare_dynamic_strings_ + // this compares two dynamic strings and works similar to that of strncmp(..) but has significant differences to strncmp(..) + // given two strings, this will return either f_equal_to or f_not_equal_to + // this is far safer than fl_compare_strings(..) as dynamic string contain size information within them + // this does not stop on f_eos and f_eos will be ignored as if it were not taking up any space, therefor a 5 character string could return f_equal_to if the 5 character string contains an f_eos anywhere within it + extern f_return_status fl_compare_dynamic_strings(const f_dynamic_string string1, const f_dynamic_string string2); +#endif // _di_fl_compare_dynamic_strings_ + +#ifndef _di_fl_compare_partial_dynamic_strings_ + // this functions identical to fl_compare_dynamic_strings, but uses offsets for both strings + extern f_return_status fl_compare_partial_dynamic_strings(const f_dynamic_string string1, const f_dynamic_string string2, const f_string_location offset1, const f_string_location offset2); +#endif // _di_fl_compare_partial_dynamic_strings_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FL_strings_h diff --git a/level_2/fll_colors/c/colors.c b/level_2/fll_colors/c/colors.c new file mode 100644 index 0000000..826bc0a --- /dev/null +++ b/level_2/fll_colors/c/colors.c @@ -0,0 +1,59 @@ +/* FLL - Level 2 + * Project: Colors + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fll_colors_load_context_ + f_return_status fll_colors_load_context(fll_color_context *data, f_bool use_light_colors){ + #ifndef _di_level_2_parameter_checking_ + if (data == 0) return f_invalid_parameter; + #endif // _di_level_2_parameter_checking_ + + f_status status = f_status_initialize; + + // switch to the appropriate terminal color mode + { + f_autochar *environment = getenv("TERM"); + + if (!environment || strncmp(environment, "linux", 6) == 0){ + data->color_list = f_colors_linux; + } else { + data->color_list = f_colors_xterminal; + } + } + + // load the colors + if (use_light_colors){ + status = fl_save_color1(&data->reset, data->color_format, data->color_list.reset); + + if (status == f_none) status = fl_save_color1(&data->warning, data->color_format, data->color_list.yellow); + if (status == f_none) status = fl_save_color2(&data->error, data->color_format, data->color_list.bold, data->color_list.red); + if (status == f_none) status = fl_save_color2(&data->title, data->color_format, data->color_list.bold, data->color_list.blue); + if (status == f_none) status = fl_save_color1(&data->notable, data->color_format, data->color_list.bold); + if (status == f_none) status = fl_save_color1(&data->important, data->color_format, data->color_list.blue); + if (status == f_none) status = fl_save_color1(&data->standout, data->color_format, data->color_list.purple); + } else { + status = fl_save_color1(&data->reset, data->color_format, data->color_list.reset); + + if (status == f_none) status = fl_save_color1(&data->warning, data->color_format, data->color_list.yellow); + if (status == f_none) status = fl_save_color2(&data->error, data->color_format, data->color_list.bold, data->color_list.red); + if (status == f_none) status = fl_save_color2(&data->title, data->color_format, data->color_list.bold, data->color_list.yellow); + if (status == f_none) status = fl_save_color1(&data->notable, data->color_format, data->color_list.bold); + if (status == f_none) status = fl_save_color2(&data->important, data->color_format, data->color_list.bold, data->color_list.green); + if (status == f_none) status = fl_save_color1(&data->standout, data->color_format, data->color_list.green); + } + + return status; + } +#endif // _di_fll_colors_load_context_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_2/fll_colors/c/colors.h b/level_2/fll_colors/c/colors.h new file mode 100644 index 0000000..6c42a44 --- /dev/null +++ b/level_2/fll_colors/c/colors.h @@ -0,0 +1,91 @@ +/* FLL - Level 2 + * Project: Colors + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * Provide standard color handling + */ +#ifndef _FLL_colors_h +#define _FLL_colors_h + +// libc includes +#include +#include + +// fll-0 includes +#include +#include +#include + +// fll-1 includes +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fll_color_context_ + typedef struct { + f_colors color_list; + f_colors_format color_format; + f_dynamic_string reset; + f_dynamic_string warning; + f_dynamic_string error; + f_dynamic_string title; + f_dynamic_string notable; + f_dynamic_string important; + f_dynamic_string standout; + f_dynamic_string normal; + f_dynamic_string normal_reset; + } fll_color_context; + + #define fll_color_context_initialize { f_colors_initialize_linux, f_colors_format_initialize_linux, f_dynamic_string_initialize, f_dynamic_string_initialize, f_dynamic_string_initialize, f_dynamic_string_initialize, f_dynamic_string_initialize, f_dynamic_string_initialize, f_dynamic_string_initialize, f_dynamic_string_initialize, f_dynamic_string_initialize } + + #define fll_new_color_context(status, color_context) \ + f_resize_dynamic_string(status, color_context.reset, f_color_max_size + 1); \ + if (status == f_none) f_resize_dynamic_string(status, color_context.warning, f_color_max_size + 1); \ + if (status == f_none) f_resize_dynamic_string(status, color_context.error, f_color_max_size + 1); \ + if (status == f_none) f_resize_dynamic_string(status, color_context.title, f_color_max_size + 1); \ + if (status == f_none) f_resize_dynamic_string(status, color_context.notable, f_color_max_size + 1); \ + if (status == f_none) f_resize_dynamic_string(status, color_context.important, f_color_max_size + 1); \ + if (status == f_none) f_resize_dynamic_string(status, color_context.standout, f_color_max_size + 1); \ + if (status == f_none) f_resize_dynamic_string(status, color_context.normal, f_color_max_size + 1); \ + if (status == f_none) f_resize_dynamic_string(status, color_context.normal_reset, f_color_max_size + 1); + + #define fll_delete_color_context(status, color_context) \ + f_delete_dynamic_string(status, color_context.reset); \ + if (status == f_none) f_delete_dynamic_string(status, color_context.warning); \ + if (status == f_none) f_delete_dynamic_string(status, color_context.error); \ + if (status == f_none) f_delete_dynamic_string(status, color_context.title); \ + if (status == f_none) f_delete_dynamic_string(status, color_context.notable); \ + if (status == f_none) f_delete_dynamic_string(status, color_context.important); \ + if (status == f_none) f_delete_dynamic_string(status, color_context.standout); \ + if (status == f_none) f_delete_dynamic_string(status, color_context.normal); \ + if (status == f_none) f_delete_dynamic_string(status, color_context.normal_reset); + + #define fll_destroy_color_context(status, color_context, size) \ + f_destroy_dynamic_string(status, color_context.reset); \ + if (status == f_none) f_destroy_dynamic_string(status, color_context.warning, size); \ + if (status == f_none) f_destroy_dynamic_string(status, color_context.error, size); \ + if (status == f_none) f_destroy_dynamic_string(status, color_context.title, size); \ + if (status == f_none) f_destroy_dynamic_string(status, color_context.notable, size); \ + if (status == f_none) f_destroy_dynamic_string(status, color_context.important, size); \ + if (status == f_none) f_destroy_dynamic_string(status, color_context.standout, size); \ + if (status == f_none) f_destroy_dynamic_string(status, color_context.normal); \ + if (status == f_none) f_destroy_dynamic_string(status, color_context.normal_reset); +#endif // _di_fll_color_context_ + +#ifndef _di_fll_colors_load_context_ + // For any application that uses the standard color contexts, this function will load the appropriate colors to the structure + // This will handle the difference betweem xorg terminals and linux consoles + // If you wish to use non-standard colors either redefine this function or don't use it + extern f_return_status fll_colors_load_context(fll_color_context *data, f_bool use_light_colors); +#endif // _di_fll_colors_load_context_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FLL_colors_h diff --git a/level_2/fll_fss/c/fss_basic.c b/level_2/fll_fss/c/fss_basic.c new file mode 100644 index 0000000..93f236e --- /dev/null +++ b/level_2/fll_fss/c/fss_basic.c @@ -0,0 +1,123 @@ +/* FLL - Level 2 + * Project: FSS + * Version: 0.2.1 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fll_fss_basic_read_ + f_return_status fll_fss_basic_read(f_dynamic_string *buffer, f_string_location *input, f_fss_objects *objects, f_fss_contents *contents){ + #ifndef _di_level_2_parameter_checking_ + if (buffer == f_null) return f_invalid_parameter; + if (objects == f_null) return f_invalid_parameter; + if (contents == f_null) return f_invalid_parameter; + #endif // _di_level_2_parameter_checking_ + + f_status status = f_status_initialize; + f_string_length initial_used = objects->used; + f_bool found_data = f_false; + + do { + if (objects->used >= objects->size){ + f_resize_fss_objects(status, (*objects), objects->used + f_fss_default_allocation_step); + + if (f_macro_test_for_allocation_errors(status)){ + return status; + } + + f_resize_fss_contents(status, (*contents), contents->used + f_fss_default_allocation_step); + + if (f_macro_test_for_allocation_errors(status)){ + return status; + } + } + + do { + status = fl_fss_basic_object_read(buffer, input, &objects->array[objects->used]); + + if (input->start >= input->stop || input->start >= buffer->used){ + if (status == fl_fss_found_object || status == fl_fss_found_object_no_content){ + objects->used++; + + fl_macro_fss_allocate_content_if_necessary(contents->array[contents->used]); + + contents->used++; + + return fl_fss_found_object_no_content; + } + + if (found_data){ + if (input->start >= buffer->used){ + return f_none_on_eos; + } + + return f_none_on_stop; + } else { + if (input->start >= buffer->used){ + return f_no_data_on_eos; + } + + return f_no_data_on_stop; + } + } + + if (status == fl_fss_found_object){ + found_data = f_true; + status = fl_fss_basic_content_read(buffer, input, &contents->array[contents->used]); + + break; + } else if (status == fl_fss_found_object_no_content){ + found_data = f_true; + + fl_macro_fss_allocate_content_if_necessary(contents->array[contents->used]); + + break; + } + } while (status == fl_fss_found_no_object); + + if (status == f_none_on_eos || status == f_none_on_stop){ + contents->array[contents->used].used++; + objects->used++; + contents->used++; + return status; + } else if (status == f_no_data_on_eos || status == f_no_data_on_stop){ + + // if at least some valid object was found, then return f_none equivelents + if (objects->used > initial_used){ + if (status == f_no_data_on_eos) return f_none_on_eos; + if (status == f_no_data_on_stop) return f_none_on_stop; + } + + return status; + } else if (status != fl_fss_found_object && status != fl_fss_found_content && status != fl_fss_found_no_content && status != fl_fss_found_object_no_content){ + return status; + // when content is found, the input->start is incremented, if content is found at input->stop, then input->start will be > input.stop + } else if (input->start >= input->stop || input->start >= buffer->used){ + if (status == fl_fss_found_object || status == fl_fss_found_content || status == fl_fss_found_no_content || status == fl_fss_found_object_no_content){ + objects->used++; + contents->used++; + } + + if (input->start >= buffer->used){ + return f_none_on_eos; + } + + return f_none_on_stop; + } + + objects->used++; + contents->used++; + } while (f_true); + + return f_unknown; + } +#endif // _di_fll_fss_basic_read_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_2/fll_fss/c/fss_basic.h b/level_2/fll_fss/c/fss_basic.h new file mode 100644 index 0000000..54c70af --- /dev/null +++ b/level_2/fll_fss/c/fss_basic.h @@ -0,0 +1,39 @@ +/* FLL - Level 2 + * Project: FSS + * Version: 0.2.1 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * This is the fss-0000 implementation + */ +#ifndef _FLL_fss_basic_h +#define _FLL_fss_basic_h + +// fll-0 includes +#include +#include +#include +#include +#include + +// fll-1 includes +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fll_fss_basic_read_ + // read an fss-0000 object and then content + extern f_return_status fll_fss_basic_read(f_dynamic_string *buffer, f_string_location *input, f_fss_objects *objects, f_fss_contents *contents); +#endif // _di_fll_fss_basic_read_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FLL_fss_basic_h diff --git a/level_2/fll_fss/c/fss_basic_list.c b/level_2/fll_fss/c/fss_basic_list.c new file mode 100644 index 0000000..3542449 --- /dev/null +++ b/level_2/fll_fss/c/fss_basic_list.c @@ -0,0 +1,123 @@ +/* FLL - Level 2 + * Project: FSS + * Version: 0.2.1 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fll_fss_basic_list_read_ + f_return_status fll_fss_basic_list_read(f_dynamic_string *buffer, f_string_location *input, f_fss_objects *objects, f_fss_contents *contents){ + #ifndef _di_level_2_parameter_checking_ + if (buffer == f_null) return f_invalid_parameter; + if (objects == f_null) return f_invalid_parameter; + if (contents == f_null) return f_invalid_parameter; + #endif // _di_level_2_parameter_checking_ + + f_status status = f_status_initialize; + f_string_length initial_used = objects->used; + f_bool found_data = f_false; + + do { + if (objects->used >= objects->size){ + f_resize_fss_objects(status, (*objects), objects->used + f_fss_default_allocation_step); + + if (f_macro_test_for_allocation_errors(status)){ + return status; + } + + f_resize_fss_contents(status, (*contents), contents->used + f_fss_default_allocation_step); + + if (f_macro_test_for_allocation_errors(status)){ + return status; + } + } + + do { + status = fl_fss_basic_list_object_read(buffer, input, &objects->array[objects->used]); + + if (input->start >= input->stop || input->start >= buffer->used){ + if (status == fl_fss_found_object || status == fl_fss_found_object_no_content){ + objects->used++; + + fl_macro_fss_allocate_content_if_necessary(contents->array[contents->used]); + + contents->used++; + + return fl_fss_found_object_no_content; + } + + if (found_data){ + if (input->start >= buffer->used){ + return f_none_on_eos; + } + + return f_none_on_stop; + } else { + if (input->start >= buffer->used){ + return f_no_data_on_eos; + } + + return f_no_data_on_stop; + } + } + + if (status == fl_fss_found_object){ + found_data = f_true; + status = fl_fss_basic_list_content_read(buffer, input, &contents->array[contents->used]); + + break; + } else if (status == fl_fss_found_object_no_content){ + found_data = f_true; + + fl_macro_fss_allocate_content_if_necessary(contents->array[contents->used]); + + break; + } + } while (status == fl_fss_found_no_object); + + if (status == f_none_on_eos || status == f_none_on_stop){ + contents->array[contents->used].used++; + objects->used++; + contents->used++; + return status; + } else if (status == f_no_data_on_eos || status == f_no_data_on_stop){ + + // if at least some valid object was found, then return f_none equivalents + if (objects->used > initial_used){ + if (status == f_no_data_on_eos) return f_none_on_eos; + if (status == f_no_data_on_stop) return f_none_on_stop; + } + + return status; + } else if (status != fl_fss_found_object && status != fl_fss_found_content && status != fl_fss_found_no_content && status != fl_fss_found_object_no_content){ + return status; + // when content is found, the input->start is incremented, if content is found at input->stop, then input->start will be > input.stop + } else if (input->start >= input->stop || input->start >= buffer->used){ + if (status == fl_fss_found_object || status == fl_fss_found_content || status == fl_fss_found_no_content || status == fl_fss_found_object_no_content){ + objects->used++; + contents->used++; + } + + if (input->start >= buffer->used){ + return f_none_on_eos; + } + + return f_none_on_stop; + } + + objects->used++; + contents->used++; + } while (f_true); + + return f_unknown; + } +#endif // _di_fll_fss_basic_list_read_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_2/fll_fss/c/fss_basic_list.h b/level_2/fll_fss/c/fss_basic_list.h new file mode 100644 index 0000000..9eb2e67 --- /dev/null +++ b/level_2/fll_fss/c/fss_basic_list.h @@ -0,0 +1,39 @@ +/* FLL - Level 2 + * Project: FSS + * Version: 0.2.1 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * This is the fss-0002 implementation + */ +#ifndef _FLL_fss_basic_list_h +#define _FLL_fss_basic_list_h + +// fll-0 includes +#include +#include +#include +#include +#include + +// fll-1 includes +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fll_fss_basic_list_read_ + // read an fss-0002 object and then content + extern f_return_status fll_fss_basic_list_read(f_dynamic_string *buffer, f_string_location *input, f_fss_objects *objects, f_fss_contents *contents); +#endif // _di_fll_fss_basic_list_read_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FLL_fss_basic_list_h diff --git a/level_2/fll_fss/c/fss_extended.c b/level_2/fll_fss/c/fss_extended.c new file mode 100644 index 0000000..7344f9a --- /dev/null +++ b/level_2/fll_fss/c/fss_extended.c @@ -0,0 +1,123 @@ +/* FLL - Level 2 + * Project: FSS + * Version: 0.2.1 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fll_fss_extended_read_ + f_return_status fll_fss_extended_read(f_dynamic_string *buffer, f_string_location *input, f_fss_objects *objects, f_fss_contents *contents){ + #ifndef _di_level_2_parameter_checking_ + if (buffer == f_null) return f_invalid_parameter; + if (objects == f_null) return f_invalid_parameter; + if (contents == f_null) return f_invalid_parameter; + #endif // _di_level_2_parameter_checking_ + + f_status status = f_status_initialize; + f_string_length initial_used = objects->used; + f_bool found_data = f_false; + + do { + if (objects->used >= objects->size){ + f_resize_fss_objects(status, (*objects), objects->used + f_fss_default_allocation_step); + + if (f_macro_test_for_allocation_errors(status)){ + return status; + } + + f_resize_fss_contents(status, (*contents), contents->used + f_fss_default_allocation_step); + + if (f_macro_test_for_allocation_errors(status)){ + return status; + } + } + + do { + status = fl_fss_extended_object_read(buffer, input, &objects->array[objects->used]); + + if (input->start >= input->stop || input->start >= buffer->used){ + if (status == fl_fss_found_object || status == fl_fss_found_object_no_content){ + objects->used++; + + fl_macro_fss_allocate_content_if_necessary(contents->array[contents->used]); + + contents->used++; + + return fl_fss_found_object_no_content; + } + + if (found_data){ + if (input->start >= buffer->used){ + return f_none_on_eos; + } + + return f_none_on_stop; + } else { + if (input->start >= buffer->used){ + return f_no_data_on_eos; + } + + return f_no_data_on_stop; + } + } + + if (status == fl_fss_found_object){ + found_data = f_true; + status = fl_fss_extended_content_read(buffer, input, &contents->array[contents->used]); + + break; + } else if (status == fl_fss_found_object_no_content){ + found_data = f_true; + + fl_macro_fss_allocate_content_if_necessary(contents->array[contents->used]); + + break; + } + } while (status == fl_fss_found_no_object); + + if (status == f_none_on_eos || status == f_none_on_stop){ + contents->array[contents->used].used++; + objects->used++; + contents->used++; + return status; + } else if (status == f_no_data_on_eos || status == f_no_data_on_stop){ + + // if at least some valid object was found, then return f_none equivelents + if (objects->used > initial_used){ + if (status == f_no_data_on_eos) return f_none_on_eos; + if (status == f_no_data_on_stop) return f_none_on_stop; + } + + return status; + } else if (status != fl_fss_found_object && status != fl_fss_found_content && status != fl_fss_found_no_content && status != fl_fss_found_object_no_content){ + return status; + // when content is found, the input->start is incremented, if content is found at input->stop, then input->start will be > input.stop + } else if (input->start >= input->stop || input->start >= buffer->used){ + if (status == fl_fss_found_object || status == fl_fss_found_content || status == fl_fss_found_no_content || status == fl_fss_found_object_no_content){ + objects->used++; + contents->used++; + } + + if (input->start >= buffer->used){ + return f_none_on_eos; + } + + return f_none_on_stop; + } + + objects->used++; + contents->used++; + } while (f_true); + + return f_unknown; + } +#endif // _di_fll_fss_extended_read_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_2/fll_fss/c/fss_extended.h b/level_2/fll_fss/c/fss_extended.h new file mode 100644 index 0000000..dd84903 --- /dev/null +++ b/level_2/fll_fss/c/fss_extended.h @@ -0,0 +1,39 @@ +/* FLL - Level 2 + * Project: FSS + * Version: 0.2.1 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * This is the fss-0001 implementation + */ +#ifndef _FLL_fss_extended_h +#define _FLL_fss_extended_h + +// fll-0 includes +#include +#include +#include +#include +#include + +// fll-1 includes +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fll_fss_extended_read_ + // read an fss-0001 object and then content + extern f_return_status fll_fss_extended_read(f_dynamic_string *buffer, f_string_location *input, f_fss_objects *objects, f_fss_contents *contents); +#endif // _di_fll_fss_extended_read_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FLL_fss_extended_h diff --git a/level_3/fss_basic_list_read/c/fss_basic_list_read.c b/level_3/fss_basic_list_read/c/fss_basic_list_read.c new file mode 100644 index 0000000..cbadded --- /dev/null +++ b/level_3/fss_basic_list_read/c/fss_basic_list_read.c @@ -0,0 +1,524 @@ +/* FLL - Level 3 + * Project: FSS + * Version: 0.2.1 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +// version printed may be used by scripts, so this will only print the version number and a newline, no extra information or colors +#ifndef _di_fss_basic_list_read_print_version_ + f_return_status fss_basic_list_read_print_version(const fss_basic_list_read_data data){ + printf("%s\n", fss_basic_list_read_version); + + return f_none; + } +#endif // _fss_basic_list_read_print_version_ + +#ifndef _di_fss_basic_list_read_print_help_ + f_return_status fss_basic_list_read_print_help(const fss_basic_list_read_data data){ + printf("\n"); + fl_print_color(f_standard_output, data.context.title, data.context.reset, " %s", fss_basic_list_read_name_long); + + printf("\n"); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, " Version %s", fss_basic_list_read_version); + + + printf("\n\n"); + fl_print_color(f_standard_output, data.context.important, data.context.reset, " Available Options: "); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_help); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_help); + printf(" Print this help message"); + + printf("\n %s", f_console_symbol_short_disable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_light); + + printf(", %s", f_console_symbol_long_disable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_light); + printf(" Output using colors that show up better on light backgrounds"); + + printf("\n %s", f_console_symbol_short_disable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_no_color); + + printf(", %s", f_console_symbol_long_disable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_no_color); + printf(" Do not output in color"); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_version); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_version); + printf(" Print only the version number"); + + + printf("\n\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_name); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_name); + printf(" Find and print content from this object name"); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_count); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_count); + printf(" Find a specific occurrence of the object"); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_total); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_total); + printf(" Print the total number of objects in this file"); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_object); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_object); + printf(" Print the object instead of the content"); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_size); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_size); + printf(" Print total lines in the given content"); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_line); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_line); + printf(" Print only the content at the given line"); + + + printf("\n\n"); + fl_print_color(f_standard_output, data.context.important, data.context.reset, " Usage: "); + + printf("\n "); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, fss_basic_list_read_name); + + printf(" "); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, "["); + + printf(" options "); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, "]"); + + printf(" "); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, "["); + + printf(" filename(s) "); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, "]"); + + + printf("\n\n"); + + return f_none; + } +#endif // _di_fss_basic_list_read_print_help_ + +#ifndef _di_fss_basic_list_read_main_ + f_return_status fss_basic_list_read_main(const f_s_int argc, const f_string argv[], fss_basic_list_read_data *data){ + f_status status = f_status_initialize; + f_status allocation_status = f_status_initialize; + + status = fl_process_parameters(argc, argv, data->parameters, fss_basic_list_read_total_parameters, &data->remaining); + + // load colors when not told to show no colors + if (data->parameters[fss_basic_list_read_parameter_no_color].result == f_console_result_none){ + fll_new_color_context(allocation_status, data->context); + + if (allocation_status == f_none){ + fll_colors_load_context(&data->context, data->parameters[fss_basic_list_read_parameter_light].result == f_console_result_found); + } else { + fprintf(f_standard_error, "Critical Error: unable to allocate memory\n"); + fss_basic_list_read_delete_data(data); + return allocation_status; + } + } + + if (status != f_none){ + if (status == f_no_data){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: One of the parameters you passed requires an additional parameter that you did not pass."); + // TODO: there is a way to identify which parameter is incorrect + // to do this, one must look for any "has_additional" and then see if the "additional" location is set to 0 + // nothing can be 0 as that represents the program name, unless argv[] is improperly created + } else if (f_macro_test_for_allocation_errors(status)){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "CRITICAL ERROR: unable to allocate memory"); + } else if (status == f_invalid_parameter){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling fl_process_parameters()"); + } else { + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fl_process_parameters()", status); + } + + fss_basic_list_read_delete_data(data); + return status; + } + + // execute parameter results + if (data->parameters[fss_basic_list_read_parameter_help].result == f_console_result_found){ + fss_basic_list_read_print_help(*data); + } else if (data->parameters[fss_basic_list_read_parameter_version].result == f_console_result_found){ + fss_basic_list_read_print_version(*data); + } else if (data->remaining.used > 0){ + f_string_length counter = f_string_length_initialize; + f_string_length current = f_string_length_initialize; + f_string_length target = f_string_length_initialize; + f_string_length found = f_string_length_initialize; + f_string_length original_size = data->file_position.total_elements; + + if (data->parameters[fss_basic_list_read_parameter_count].result == f_console_result_additional){ + target = (f_string_length) atoll(argv[data->parameters[fss_basic_list_read_parameter_count].additional]); + } + + for (; counter < data->remaining.used; counter++){ + f_file file = f_file_initialize; + + status = f_file_open(&file, argv[data->remaining.array[counter]]); + + data->file_position.total_elements = original_size; + + if (status != f_none){ + if (status == f_invalid_parameter){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling f_file_open()"); + } else if (status == f_file_not_found){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Unable to find the file '%s'", argv[data->remaining.array[counter]]); + } else if (status == f_file_open_error){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Unable to open the file '%s'", argv[data->remaining.array[counter]]); + } else if (status == f_file_descriptor_error){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: File descriptor error while trying to open the file '%s'", argv[data->remaining.array[counter]]); + } else { + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling f_file_open()", status); + } + + fss_basic_list_read_delete_data(data); + return status; + } + + // TODO: this file size set functionality might be turned into an fl_file (or f_file) function + if (data->file_position.total_elements == 0){ + fseek(file.file, 0, SEEK_END); + + data->file_position.total_elements = ftell(file.file); + + // skip past empty files + if (data->file_position.total_elements == 0){ + f_file_close(&file); + continue; + } + + fseek(file.file, 0, SEEK_SET); + } + + status = fl_file_read(file, data->file_position, &data->buffer); + + f_file_close(&file); + + if (status != f_none && status != f_none_on_eof && status != f_none_on_eos){ + if (status == f_invalid_parameter){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling fl_file_read()"); + } else if (status == f_overflow){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Integer overflow while trying to buffer the file '%s'", argv[data->remaining.array[counter]]); + } else if (status == f_file_not_open){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: The file '%s' is no longer open", argv[data->remaining.array[counter]]); + } else if (status == f_file_seek_error){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: A seek error occurred while accessing the file '%s'", argv[data->remaining.array[counter]]); + } else if (status == f_file_read_error){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: A read error occurred while accessing the file '%s'", argv[data->remaining.array[counter]]); + } else if (f_macro_test_for_allocation_errors(status)){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "CRITICAL ERROR: unable to allocate memory"); + } else { + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fl_file_read()", status); + } + + fss_basic_list_read_delete_data(data); + return status; + } + + { + f_string_location input = f_string_location_initialize; + + input.stop = data->buffer.used - 1; + + status = fll_fss_basic_list_read(&data->buffer, &input, &data->objects, &data->contents); + } + + if (status != f_none && status != f_none_on_eos && status != f_none_on_stop && status != fl_fss_found_object_no_content){ + if (status == f_invalid_parameter){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling fll_fss_basic_list_read() for the file '%s'", argv[data->remaining.array[counter]]); + + fss_basic_list_read_delete_data(data); + return status; + } else if (status == f_no_data_on_eos || status == f_no_data || status == f_no_data_on_stop || status == f_no_data_on_eof){ + // not an error in this case + } else if (f_macro_test_for_allocation_errors(status)){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "CRITICAL ERROR: unable to allocate memory"); + + fss_basic_list_read_delete_data(data); + return status; + } else { + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fll_fss_basic_list_read() for the file '%s'", status, argv[data->remaining.array[counter]]); + } + + // clear buffers, then attempt the next file + f_delete_fss_contents(allocation_status, data->contents); + f_delete_fss_objects(allocation_status, data->objects); + f_delete_dynamic_string(allocation_status, data->buffer); + + continue; + } + + // now that all of the files have been read, process the objects and contents + if (data->parameters[fss_basic_list_read_parameter_total].result == f_console_result_found){ + fprintf(f_standard_output, "%u\n", (unsigned int) data->objects.used); + } else { + current = 0; + + if (data->parameters[fss_basic_list_read_parameter_name].result == f_console_result_none){ + if (data->parameters[fss_basic_list_read_parameter_object].result == f_console_result_none){ + for (; current < data->objects.used; current++){ + if (data->parameters[fss_basic_list_read_parameter_count].result == f_console_result_none || (data->parameters[fss_basic_list_read_parameter_count].result == f_console_result_additional && found == target)){ + + if (data->parameters[fss_basic_list_read_parameter_size].result == f_console_result_found){ + if (data->contents.array[current].used > 0){ + f_string_length counter = data->contents.array[current].array[0].start; + f_string_length size = 0; + + for (; counter <= data->contents.array[current].array[0].stop; counter++){ + if (data->buffer.string[counter] == f_eol) size++; + } // for + + // the last newline is never present + size++; + + fprintf(f_standard_output, "%u\n", (unsigned int) size); + } else { + fprintf(f_standard_output, "0\n"); + } + } else if (data->parameters[fss_basic_list_read_parameter_line].result == f_console_result_additional){ + if (data->contents.array[current].used > 0){ + f_string_length counter = data->contents.array[current].array[0].start; + f_string_length position = 0; + f_string_length target = (f_string_length) atoll(argv[data->parameters[fss_basic_list_read_parameter_line].additional]); + f_string_location range = f_string_location_initialize; + + // use an invalid range to communicate range not found + range.start = 1; + range.stop = 0; + + for (; counter <= data->contents.array[current].array[0].stop; counter++){ + if (position == target){ + range.start = counter; + + // explicit use of < instead of <= is done here so that the range.stop will always be accurate + for (; counter < data->contents.array[current].array[0].stop; counter++){ + if (data->buffer.string[counter] == f_eol){ + break; + } + } // for + + range.stop = counter; + break; + } + + if (data->buffer.string[counter] == f_eol){ + position++; + } + } // for + + if (range.start <= range.stop){ + f_print_partial_dynamic_string(f_standard_output, data->buffer, range); + } + } + } else { + if (data->contents.array[current].used > 0){ + f_print_partial_dynamic_string(f_standard_output, data->buffer, data->contents.array[current].array[0]); + fprintf(f_standard_output, "\n"); + } + } + } + + if (data->parameters[fss_basic_list_read_parameter_count].result == f_console_result_additional){ + if (found == target){ + break; + } else { + found++; + } + } + } // for + } else { + for (; current < data->objects.used; current++){ + if (data->parameters[fss_basic_list_read_parameter_count].result == f_console_result_none || (data->parameters[fss_basic_list_read_parameter_count].result == f_console_result_additional && found == target)){ + f_print_partial_dynamic_string(f_standard_output, data->buffer, data->objects.array[current]); + fprintf(f_standard_output, "\n"); + } + + if (data->parameters[fss_basic_list_read_parameter_count].result == f_console_result_additional){ + if (found == target){ + break; + } else { + found++; + } + } + } // for + } + } else { + current = 0; + + f_string_length name_length = f_string_length_initialize; + f_string_length argv_length = f_string_length_initialize; + + if (data->parameters[fss_basic_list_read_parameter_name].result == f_console_result_additional){ + argv_length = strlen(argv[data->parameters[fss_basic_list_read_parameter_name].additional]); + + if (data->parameters[fss_basic_list_read_parameter_object].result == f_console_result_none){ + for (; current < data->objects.used; current++){ + name_length = data->objects.array[current].stop - data->objects.array[current].start + 1; + + if (name_length == argv_length){ + if (fl_compare_strings(data->buffer.string + data->objects.array[current].start, argv[data->parameters[fss_basic_list_read_parameter_name].additional], name_length, argv_length) == f_equal_to){ + + if (data->parameters[fss_basic_list_read_parameter_size].result == f_console_result_found){ + if (data->contents.array[current].used > 0){ + f_string_length counter = data->contents.array[current].array[0].start; + f_string_length size = 0; + + for (; counter <= data->contents.array[current].array[0].stop; counter++){ + if (data->buffer.string[counter] == f_eol) size++; + } // for + + // the last newline is never present + size++; + + fprintf(f_standard_output, "%u\n", (unsigned int) size); + } else { + fprintf(f_standard_output, "0\n"); + } + } else if (data->parameters[fss_basic_list_read_parameter_line].result == f_console_result_additional){ + if (data->contents.array[current].used > 0){ + f_string_length counter = data->contents.array[current].array[0].start; + f_string_length position = 0; + f_string_length target = (f_string_length) atoll(argv[data->parameters[fss_basic_list_read_parameter_line].additional]); + f_string_location range = f_string_location_initialize; + + // use an invalid range to communicate range not found + range.start = 1; + range.stop = 0; + + for (; counter <= data->contents.array[current].array[0].stop; counter++){ + if (position == target){ + range.start = counter; + + // explicit use of < instead of <= is done here so that the range.stop will always be accurate + for (; counter < data->contents.array[current].array[0].stop; counter++){ + if (data->buffer.string[counter] == f_eol){ + break; + } + } // for + + range.stop = counter; + break; + } + + if (data->buffer.string[counter] == f_eol){ + position++; + } + } // for + + if (range.start <= range.stop){ + f_print_partial_dynamic_string(f_standard_output, data->buffer, range); + } + } + } else { + if (data->parameters[fss_basic_list_read_parameter_count].result == f_console_result_none || (data->parameters[fss_basic_list_read_parameter_count].result == f_console_result_additional && found == target)){ + if (data->contents.array[current].used > 0){ + f_print_partial_dynamic_string(f_standard_output, data->buffer, data->contents.array[current].array[0]); + fprintf(f_standard_output, "\n"); + } + } + } + + if (data->parameters[fss_basic_list_read_parameter_count].result == f_console_result_additional){ + if (found == target){ + break; + } else { + found++; + } + } + } + } + } // for + } else { + // when and because the object parameter is specified, the name parameter refers to the content instead of the object + // therefore, make the search on the content and display the object + for (; current < data->contents.used; current++){ + if (data->contents.array[current].used > 0){ + name_length = data->contents.array[current].array[0].stop - data->contents.array[current].array[0].start + 1; + + if (name_length == argv_length){ + if (fl_compare_strings(data->buffer.string + data->contents.array[current].array[0].start, argv[data->parameters[fss_basic_list_read_parameter_name].additional], name_length, argv_length) == f_equal_to){ + if (data->parameters[fss_basic_list_read_parameter_count].result == f_console_result_none || (data->parameters[fss_basic_list_read_parameter_count].result == f_console_result_additional && found == target)){ + f_print_partial_dynamic_string(f_standard_output, data->buffer, data->objects.array[current]); + fprintf(f_standard_output, "\n"); + } + + if (data->parameters[fss_basic_list_read_parameter_count].result == f_console_result_additional){ + if (found == target){ + break; + } else { + found++; + } + } + } + } + } + } // for + } + } + } + } + + // clear buffers before repeating the loop + f_delete_fss_contents(allocation_status, data->contents); + f_delete_fss_objects(allocation_status, data->objects); + f_delete_dynamic_string(allocation_status, data->buffer); + } // for + } else { + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: you failed to specify one or more files"); + } + + fss_basic_list_read_delete_data(data); + return status; + } +#endif // _di_fss_basic_list_read_main_ + +#ifndef _di_fss_basic_list_read_delete_data_ + f_return_status fss_basic_list_read_delete_data(fss_basic_list_read_data *data){ + f_status status = f_status_initialize; + + f_delete_fss_contents(status, data->contents); + f_delete_fss_objects(status, data->objects); + f_delete_dynamic_string(status, data->buffer); + f_delete_string_lengths(status, data->remaining); + + fll_delete_color_context(status, data->context); + + return f_none; + } +#endif // _di_fss_basic_list_read_delete_data_ + + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_3/fss_basic_list_read/c/fss_basic_list_read.h b/level_3/fss_basic_list_read/c/fss_basic_list_read.h new file mode 100644 index 0000000..6ca8402 --- /dev/null +++ b/level_3/fss_basic_list_read/c/fss_basic_list_read.h @@ -0,0 +1,146 @@ +/* FLL - Level 3 + * Project: FSS + * Version: 0.2.1 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * This is the FSS Basic List Read program + * This program utilizes the Featureless Linux Library. + * This program processes files or other input in fss format and stores the results in the fss_basic_list_read_data + */ +#ifndef _fss_basic_list_read_h + +// libc includes +#include +#include +#include +#include + +// fll-0 includes +#include +#include +#include +#include +#include + +// fll-1 includes +#include +#include +#include +#include +#include +#include + +// fll-2 includes +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fss_basic_list_read_version_ + #define fss_basic_list_read_major_version "0" + #define fss_basic_list_read_minor_version "2" + #define fss_basic_list_read_micro_version "1" + #define fss_basic_list_read_version fss_basic_list_read_major_version "." fss_basic_list_read_minor_version "." fss_basic_list_read_micro_version +#endif // _di_fss_basic_list_read_version_ + +#ifndef _di_fss_basic_list_read_name_ + #define fss_basic_list_read_name "fss_basic_list_read" + #define fss_basic_list_read_name_long "FSS Basic List Read" +#endif // _di_fss_basic_list_read_name_ + +#ifndef _di_fss_basic_list_read_defines_ + #define f_console_standard_short_name "n" + #define f_console_standard_short_count "c" + #define f_console_standard_short_total "t" + #define f_console_standard_short_object "o" + #define f_console_standard_short_size "s" + #define f_console_standard_short_line "l" + + #define f_console_standard_long_name "name" + #define f_console_standard_long_count "count" + #define f_console_standard_long_total "total" + #define f_console_standard_long_object "object" + #define f_console_standard_long_size "size" + #define f_console_standard_long_line "line" + + enum { + fss_basic_list_read_parameter_help, + fss_basic_list_read_parameter_light, + fss_basic_list_read_parameter_no_color, + fss_basic_list_read_parameter_version, + + fss_basic_list_read_parameter_name, + fss_basic_list_read_parameter_count, + fss_basic_list_read_parameter_total, + fss_basic_list_read_parameter_object, + fss_basic_list_read_parameter_size, + fss_basic_list_read_parameter_line, + }; + + #define f_console_parameter_initialize_fss_basic_list_read \ + { \ + f_console_parameter_initialize(f_console_standard_short_help, f_console_standard_long_help, 0, 0, f_false, f_console_type_normal, 0), \ + f_console_parameter_initialize(f_console_standard_short_light, f_console_standard_long_light, 0, 0, f_false, f_console_type_inverse, 0), \ + f_console_parameter_initialize(f_console_standard_short_no_color, f_console_standard_long_no_color, 0, 0, f_false, f_console_type_inverse, 0), \ + f_console_parameter_initialize(f_console_standard_short_version, f_console_standard_long_version, 0, 0, f_false, f_console_type_normal, 0), \ + f_console_parameter_initialize(f_console_standard_short_name, f_console_standard_long_name, 0, 0, f_true, f_console_type_normal, 0), \ + f_console_parameter_initialize(f_console_standard_short_count, f_console_standard_long_count, 0, 0, f_true, f_console_type_normal, 0), \ + f_console_parameter_initialize(f_console_standard_short_total, f_console_standard_long_total, 0, 0, f_false, f_console_type_normal, 0), \ + f_console_parameter_initialize(f_console_standard_short_object, f_console_standard_long_object, 0, 0, f_false, f_console_type_normal, 0), \ + f_console_parameter_initialize(f_console_standard_short_size, f_console_standard_long_size, 0, 0, f_false, f_console_type_normal, 0), \ + f_console_parameter_initialize(f_console_standard_short_line, f_console_standard_long_line, 0, 0, f_true, f_console_type_normal, 0), \ + } + + #define fss_basic_list_read_total_parameters 10 +#endif // _di_fss_basic_list_read_defines_ + +#ifndef _di_fss_basic_list_read_data_ + typedef struct { + f_console_parameter parameters[fss_basic_list_read_total_parameters]; + + f_dynamic_string buffer; + f_fss_objects objects; + f_fss_contents contents; + f_file_position file_position; + f_string_lengths remaining; + + fll_color_context context; + } fss_basic_list_read_data; + + #define fss_basic_list_read_data_initialize \ + { \ + f_console_parameter_initialize_fss_basic_list_read, \ + f_dynamic_string_initialize, \ + f_fss_objects_initialize, \ + f_fss_contents_initialize, \ + f_file_position_initialize, \ + f_string_lengths_initialize, \ + fll_color_context_initialize, \ + } +#endif // _di_fss_basic_list_read_data_ + +#ifndef _di_fss_basic_list_read_print_version_ + extern f_return_status fss_basic_list_read_print_version(const fss_basic_list_read_data data); +#endif // _di_fss_basic_list_read_print_version_ + +#ifndef _di_fss_basic_list_read_print_help_ + extern f_return_status fss_basic_list_read_print_help(const fss_basic_list_read_data data); +#endif // _di_fss_basic_list_read_print_help_ + +#ifndef _di_fss_basic_list_read_main_ + extern f_return_status fss_basic_list_read_main(const f_s_int argc, const f_string argv[], fss_basic_list_read_data *data); +#endif // _di_fss_basic_list_read_main_ + +#ifndef _di_fss_basic_list_read_delete_data_ + extern f_return_status fss_basic_list_read_delete_data(fss_basic_list_read_data *data); +#endif // _di_fss_basic_list_read_delete_data_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _fss_basic_list_read_h diff --git a/level_3/fss_basic_list_read/c/main.c b/level_3/fss_basic_list_read/c/main.c new file mode 100644 index 0000000..bd82af9 --- /dev/null +++ b/level_3/fss_basic_list_read/c/main.c @@ -0,0 +1,12 @@ +#include + +int main(const f_s_int argc, const f_string argv[]){ + f_status status = f_status_initialize; + fss_basic_list_read_data data = fss_basic_list_read_data_initialize; + + status = fss_basic_list_read_main(argc, argv, &data); + + if (status == f_none) return 0; + + return status; +} diff --git a/level_3/fss_basic_read/c/fss_basic_read.c b/level_3/fss_basic_read/c/fss_basic_read.c new file mode 100644 index 0000000..27481f4 --- /dev/null +++ b/level_3/fss_basic_read/c/fss_basic_read.c @@ -0,0 +1,409 @@ +/* FLL - Level 3 + * Project: FSS + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +// version printed may be used by scripts, so this will only print the version number and a newline, no extra information or colors +#ifndef _di_fss_basic_read_print_version_ + f_return_status fss_basic_read_print_version(const fss_basic_read_data data){ + printf("%s\n", fss_basic_read_version); + + return f_none; + } +#endif // _fss_basic_read_print_version_ + +#ifndef _di_fss_basic_read_print_help_ + f_return_status fss_basic_read_print_help(const fss_basic_read_data data){ + printf("\n"); + fl_print_color(f_standard_output, data.context.title, data.context.reset, " %s", fss_basic_read_name_long); + + printf("\n"); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, " Version %s", fss_basic_read_version); + + + printf("\n\n"); + fl_print_color(f_standard_output, data.context.important, data.context.reset, " Available Options: "); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_help); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_help); + printf(" Print this help message"); + + printf("\n %s", f_console_symbol_short_disable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_light); + + printf(", %s", f_console_symbol_long_disable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_light); + printf(" Output using colors that show up better on light backgrounds"); + + printf("\n %s", f_console_symbol_short_disable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_no_color); + + printf(", %s", f_console_symbol_long_disable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_no_color); + printf(" Do not output in color"); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_version); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_version); + printf(" Print only the version number"); + + + printf("\n\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_name); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_name); + printf(" Find and print content from this object name"); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_count); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_count); + printf(" Find a specific occurrence of the object"); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_total); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_total); + printf(" Print the total number of objects in this file"); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_object); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_object); + printf(" Print the object instead of the content"); + + + printf("\n\n"); + fl_print_color(f_standard_output, data.context.important, data.context.reset, " Usage: "); + + printf("\n "); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, fss_basic_read_name); + + printf(" "); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, "["); + + printf(" options "); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, "]"); + + printf(" "); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, "["); + + printf(" filename(s) "); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, "]"); + + + printf("\n\n"); + + return f_none; + } +#endif // _di_fss_basic_read_print_help_ + +#ifndef _di_fss_basic_read_main_ + f_return_status fss_basic_read_main(const f_s_int argc, const f_string argv[], fss_basic_read_data *data){ + f_status status = f_status_initialize; + f_status allocation_status = f_status_initialize; + + status = fl_process_parameters(argc, argv, data->parameters, fss_basic_read_total_parameters, &data->remaining); + + // load colors when not told to show no colors + if (data->parameters[fss_basic_read_parameter_no_color].result == f_console_result_none){ + fll_new_color_context(allocation_status, data->context); + + if (allocation_status == f_none){ + fll_colors_load_context(&data->context, data->parameters[fss_basic_read_parameter_light].result == f_console_result_found); + } else { + fprintf(f_standard_error, "Critical Error: unable to allocate memory\n"); + fss_basic_read_delete_data(data); + return allocation_status; + } + } + + if (status != f_none){ + if (status == f_no_data){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: One of the parameters you passed requires an additional parameter that you did not pass."); + // TODO: there is a way to identify which parameter is incorrect + // to do this, one must look for any "has_additional" and then see if the "additional" location is set to 0 + // nothing can be 0 as that represents the program name, unless argv[] is improperly created + } else if (f_macro_test_for_allocation_errors(status)){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "CRITICAL ERROR: unable to allocate memory"); + } else if (status == f_invalid_parameter){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling fl_process_parameters()"); + } else { + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fl_process_parameters()", status); + } + + fss_basic_read_delete_data(data); + return status; + } + + // execute parameter results + if (data->parameters[fss_basic_read_parameter_help].result == f_console_result_found){ + fss_basic_read_print_help(*data); + } else if (data->parameters[fss_basic_read_parameter_version].result == f_console_result_found){ + fss_basic_read_print_version(*data); + } else if (data->remaining.used > 0){ + f_string_length counter = f_string_length_initialize; + f_string_length current = f_string_length_initialize; + f_string_length target = f_string_length_initialize; + f_string_length found = f_string_length_initialize; + f_string_length original_size = data->file_position.total_elements; + + if (data->parameters[fss_basic_read_parameter_count].result == f_console_result_additional){ + target = (f_string_length) atoll(argv[data->parameters[fss_basic_read_parameter_count].additional]); + } + + for (; counter < data->remaining.used; counter++){ + f_file file = f_file_initialize; + + status = f_file_open(&file, argv[data->remaining.array[counter]]); + + data->file_position.total_elements = original_size; + + if (status != f_none){ + if (status == f_invalid_parameter){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling f_file_open()"); + } else if (status == f_file_not_found){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Unable to find the file '%s'", argv[data->remaining.array[counter]]); + } else if (status == f_file_open_error){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Unable to open the file '%s'", argv[data->remaining.array[counter]]); + } else if (status == f_file_descriptor_error){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: File descriptor error while trying to open the file '%s'", argv[data->remaining.array[counter]]); + } else { + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling f_file_open()", status); + } + + fss_basic_read_delete_data(data); + return status; + } + + // TODO: this file size set functionality might be turned into an fl_file (or f_file) function + if (data->file_position.total_elements == 0){ + fseek(file.file, 0, SEEK_END); + + data->file_position.total_elements = ftell(file.file); + + // skip past empty files + if (data->file_position.total_elements == 0){ + f_file_close(&file); + continue; + } + + fseek(file.file, 0, SEEK_SET); + } + + status = fl_file_read(file, data->file_position, &data->buffer); + + f_file_close(&file); + + if (status != f_none && status != f_none_on_eof && status != f_none_on_eos){ + if (status == f_invalid_parameter){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling fl_file_read()"); + } else if (status == f_overflow){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Integer overflow while trying to buffer the file '%s'", argv[data->remaining.array[counter]]); + } else if (status == f_file_not_open){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: The file '%s' is no longer open", argv[data->remaining.array[counter]]); + } else if (status == f_file_seek_error){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: A seek error occurred while accessing the file '%s'", argv[data->remaining.array[counter]]); + } else if (status == f_file_read_error){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: A read error occurred while accessing the file '%s'", argv[data->remaining.array[counter]]); + } else if (f_macro_test_for_allocation_errors(status)){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "CRITICAL ERROR: unable to allocate memory"); + } else { + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fl_file_read()", status); + } + + fss_basic_read_delete_data(data); + return status; + } + + { + f_string_location input = f_string_location_initialize; + + input.stop = data->buffer.used - 1; + + status = fll_fss_basic_read(&data->buffer, &input, &data->objects, &data->contents); + } + + if (status != f_none && status != f_none_on_eos && status != f_none_on_stop && status != fl_fss_found_object_no_content){ + if (status == f_invalid_parameter){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling fll_fss_basic_list_read() for the file '%s'", argv[data->remaining.array[counter]]); + + fss_basic_read_delete_data(data); + return status; + } else if (status == f_no_data_on_eos || status == f_no_data || status == f_no_data_on_stop || status == f_no_data_on_eof){ + // not an error in this case + } else if (f_macro_test_for_allocation_errors(status)){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "CRITICAL ERROR: unable to allocate memory"); + + fss_basic_read_delete_data(data); + return status; + } else { + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fll_fss_basic_list_read() for the file '%s'", status, argv[data->remaining.array[counter]]); + } + + // clear buffers, then attempt the next file + f_delete_fss_contents(allocation_status, data->contents); + f_delete_fss_objects(allocation_status, data->objects); + f_delete_dynamic_string(allocation_status, data->buffer); + + continue; + } + + // now that all of the files have been read, process the objects and contents + if (data->parameters[fss_basic_read_parameter_total].result == f_console_result_found){ + fprintf(f_standard_output, "%u\n", (unsigned int) data->objects.used); + } else { + current = 0; + + if (data->parameters[fss_basic_read_parameter_name].result == f_console_result_none){ + if (data->parameters[fss_basic_read_parameter_object].result == f_console_result_none){ + for (; current < data->objects.used; current++){ + if (data->parameters[fss_basic_read_parameter_count].result == f_console_result_none || (data->parameters[fss_basic_read_parameter_count].result == f_console_result_additional && found == target)){ + if (data->contents.array[current].used > 0){ + f_print_partial_dynamic_string(f_standard_output, data->buffer, data->contents.array[current].array[0]); + fprintf(f_standard_output, "\n"); + } else { + // for all objects with no data, print a newline + fprintf(f_standard_output, "\n"); + } + } + + if (data->parameters[fss_basic_read_parameter_count].result == f_console_result_additional){ + if (found == target){ + break; + } else { + found++; + } + } + } // for + } else { + for (; current < data->objects.used; current++){ + if (data->parameters[fss_basic_read_parameter_count].result == f_console_result_none || (data->parameters[fss_basic_read_parameter_count].result == f_console_result_additional && found == target)){ + f_print_partial_dynamic_string(f_standard_output, data->buffer, data->objects.array[current]); + fprintf(f_standard_output, "\n"); + } + + if (data->parameters[fss_basic_read_parameter_count].result == f_console_result_additional){ + if (found == target){ + break; + } else { + found++; + } + } + } // for + } + } else { + current = 0; + + f_string_length name_length = f_string_length_initialize; + f_string_length argv_length = f_string_length_initialize; + + if (data->parameters[fss_basic_read_parameter_name].result == f_console_result_additional){ + argv_length = strlen(argv[data->parameters[fss_basic_read_parameter_name].additional]); + + if (data->parameters[fss_basic_read_parameter_object].result == f_console_result_none){ + for (; current < data->objects.used; current++){ + name_length = data->objects.array[current].stop - data->objects.array[current].start + 1; + + if (name_length == argv_length){ + if (fl_compare_strings(data->buffer.string + data->objects.array[current].start, argv[data->parameters[fss_basic_read_parameter_name].additional], name_length, argv_length) == f_equal_to){ + + if (data->parameters[fss_basic_read_parameter_count].result == f_console_result_none || (data->parameters[fss_basic_read_parameter_count].result == f_console_result_additional && found == target)){ + if (data->contents.array[current].used > 0){ + f_print_partial_dynamic_string(f_standard_output, data->buffer, data->contents.array[current].array[0]); + fprintf(f_standard_output, "\n"); + } else { + // for all objects with no data, print a newline + fprintf(f_standard_output, "\n"); + } + } + + if (data->parameters[fss_basic_read_parameter_count].result == f_console_result_additional){ + if (found == target){ + break; + } else { + found++; + } + } + } + } + } // for + } else { + // when and because the object parameter is specified, the name parameter refers to the content instead of the object + // therefore, make the search on the content and display the object + for (; current < data->contents.used; current++){ + if (data->contents.array[current].used > 0){ + name_length = data->contents.array[current].array[0].stop - data->contents.array[current].array[0].start + 1; + + if (name_length == argv_length){ + if (fl_compare_strings(data->buffer.string + data->contents.array[current].array[0].start, argv[data->parameters[fss_basic_read_parameter_name].additional], name_length, argv_length) == f_equal_to){ + if (data->parameters[fss_basic_read_parameter_count].result == f_console_result_none || (data->parameters[fss_basic_read_parameter_count].result == f_console_result_additional && found == target)){ + f_print_partial_dynamic_string(f_standard_output, data->buffer, data->objects.array[current]); + fprintf(f_standard_output, "\n"); + } + + if (data->parameters[fss_basic_read_parameter_count].result == f_console_result_additional){ + if (found == target){ + break; + } else { + found++; + } + } + } + } + } + } // for + } + } + } + } + + // clear buffers before repeating the loop + f_delete_fss_contents(allocation_status, data->contents); + f_delete_fss_objects(allocation_status, data->objects); + f_delete_dynamic_string(allocation_status, data->buffer); + } // for + } else { + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: you failed to specify one or more files"); + } + + fss_basic_read_delete_data(data); + return status; + } +#endif // _di_fss_basic_read_main_ + +#ifndef _di_fss_basic_read_delete_data_ + f_return_status fss_basic_read_delete_data(fss_basic_read_data *data){ + f_status status = f_status_initialize; + + f_delete_fss_contents(status, data->contents); + f_delete_fss_objects(status, data->objects); + f_delete_dynamic_string(status, data->buffer); + f_delete_string_lengths(status, data->remaining); + + fll_delete_color_context(status, data->context); + + return f_none; + } +#endif // _di_fss_basic_read_delete_data_ + + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_3/fss_basic_read/c/fss_basic_read.h b/level_3/fss_basic_read/c/fss_basic_read.h new file mode 100644 index 0000000..dbfe98b --- /dev/null +++ b/level_3/fss_basic_read/c/fss_basic_read.h @@ -0,0 +1,138 @@ +/* FLL - Level 3 + * Project: FSS + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * This is the FSS Basic Read program + * This program utilizes the Featureless Linux Library. + * This program processes files or other input in fss format and stores the results in the fss_basic_read_data + */ +#ifndef _fss_basic_read_h + +// libc includes +#include +#include +#include +#include + +// fll-0 includes +#include +#include +#include +#include +#include + +// fll-1 includes +#include +#include +#include +#include +#include +#include + +// fll-2 includes +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fss_basic_read_version_ + #define fss_basic_read_major_version "0" + #define fss_basic_read_minor_version "2" + #define fss_basic_read_micro_version "0" + #define fss_basic_read_version fss_basic_read_major_version "." fss_basic_read_minor_version "." fss_basic_read_micro_version +#endif // _di_fss_basic_read_version_ + +#ifndef _di_fss_basic_read_name_ + #define fss_basic_read_name "fss_basic_read" + #define fss_basic_read_name_long "FSS Basic Read" +#endif // _di_fss_basic_read_name_ + +#ifndef _di_fss_basic_read_defines_ + #define f_console_standard_short_name "n" + #define f_console_standard_short_count "c" + #define f_console_standard_short_total "t" + #define f_console_standard_short_object "o" + + #define f_console_standard_long_name "name" + #define f_console_standard_long_count "count" + #define f_console_standard_long_total "total" + #define f_console_standard_long_object "object" + + enum { + fss_basic_read_parameter_help, + fss_basic_read_parameter_light, + fss_basic_read_parameter_no_color, + fss_basic_read_parameter_version, + + fss_basic_read_parameter_name, + fss_basic_read_parameter_count, + fss_basic_read_parameter_total, + fss_basic_read_parameter_object, + }; + + #define f_console_parameter_initialize_fss_basic_read \ + { \ + f_console_parameter_initialize(f_console_standard_short_help, f_console_standard_long_help, 0, 0, f_false, f_console_type_normal, 0), \ + f_console_parameter_initialize(f_console_standard_short_light, f_console_standard_long_light, 0, 0, f_false, f_console_type_inverse, 0), \ + f_console_parameter_initialize(f_console_standard_short_no_color, f_console_standard_long_no_color, 0, 0, f_false, f_console_type_inverse, 0), \ + f_console_parameter_initialize(f_console_standard_short_version, f_console_standard_long_version, 0, 0, f_false, f_console_type_normal, 0), \ + f_console_parameter_initialize(f_console_standard_short_name, f_console_standard_long_name, 0, 0, f_true, f_console_type_normal, 0), \ + f_console_parameter_initialize(f_console_standard_short_count, f_console_standard_long_count, 0, 0, f_true, f_console_type_normal, 0), \ + f_console_parameter_initialize(f_console_standard_short_total, f_console_standard_long_total, 0, 0, f_false, f_console_type_normal, 0), \ + f_console_parameter_initialize(f_console_standard_short_object, f_console_standard_long_object, 0, 0, f_false, f_console_type_normal, 0), \ + } + + #define fss_basic_read_total_parameters 8 +#endif // _di_fss_basic_read_defines_ + +#ifndef _di_fss_basic_read_data_ + typedef struct { + f_console_parameter parameters[fss_basic_read_total_parameters]; + + f_dynamic_string buffer; + f_fss_objects objects; + f_fss_contents contents; + f_file_position file_position; + f_string_lengths remaining; + + fll_color_context context; + } fss_basic_read_data; + + #define fss_basic_read_data_initialize \ + { \ + f_console_parameter_initialize_fss_basic_read, \ + f_dynamic_string_initialize, \ + f_fss_objects_initialize, \ + f_fss_contents_initialize, \ + f_file_position_initialize, \ + f_string_lengths_initialize, \ + fll_color_context_initialize, \ + } +#endif // _di_fss_basic_read_data_ + +#ifndef _di_fss_basic_read_print_version_ + extern f_return_status fss_basic_read_print_version(const fss_basic_read_data data); +#endif // _di_fss_basic_read_print_version_ + +#ifndef _di_fss_basic_read_print_help_ + extern f_return_status fss_basic_read_print_help(const fss_basic_read_data data); +#endif // _di_fss_basic_read_print_help_ + +#ifndef _di_fss_basic_read_main_ + extern f_return_status fss_basic_read_main(const f_s_int argc, const f_string argv[], fss_basic_read_data *data); +#endif // _di_fss_basic_read_main_ + +#ifndef _di_fss_basic_read_delete_data_ + extern f_return_status fss_basic_read_delete_data(fss_basic_read_data *data); +#endif // _di_fss_basic_read_delete_data_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _fss_basic_read_h diff --git a/level_3/fss_basic_read/c/main.c b/level_3/fss_basic_read/c/main.c new file mode 100644 index 0000000..2149f61 --- /dev/null +++ b/level_3/fss_basic_read/c/main.c @@ -0,0 +1,12 @@ +#include + +int main(const f_s_int argc, const f_string argv[]){ + f_status status = f_status_initialize; + fss_basic_read_data data = fss_basic_read_data_initialize; + + status = fss_basic_read_main(argc, argv, &data); + + if (status == f_none) return 0; + + return status; +} diff --git a/level_3/fss_extended_read/c/fss_extended_read.c b/level_3/fss_extended_read/c/fss_extended_read.c new file mode 100644 index 0000000..d9522ae --- /dev/null +++ b/level_3/fss_extended_read/c/fss_extended_read.c @@ -0,0 +1,421 @@ +/* FLL - Level 3 + * Project: FSS + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +// version printed may be used by scripts, so this will only print the version number and a newline, no extra information or colors +#ifndef _di_fss_extended_read_print_version_ + f_return_status fss_extended_read_print_version(const fss_extended_read_data data){ + printf("%s\n", fss_extended_read_version); + + return f_none; + } +#endif // _fss_extended_read_print_version_ + +#ifndef _di_fss_extended_read_print_help_ + f_return_status fss_extended_read_print_help(const fss_extended_read_data data){ + printf("\n"); + fl_print_color(f_standard_output, data.context.title, data.context.reset, " %s", fss_extended_read_name_long); + + printf("\n"); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, " Version %s", fss_extended_read_version); + + + printf("\n\n"); + fl_print_color(f_standard_output, data.context.important, data.context.reset, " Available Options: "); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_help); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_help); + printf(" Print this help message"); + + printf("\n %s", f_console_symbol_short_disable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_light); + + printf(", %s", f_console_symbol_long_disable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_light); + printf(" Output using colors that show up better on light backgrounds"); + + printf("\n %s", f_console_symbol_short_disable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_no_color); + + printf(", %s", f_console_symbol_long_disable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_no_color); + printf(" Do not output in color"); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_version); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_version); + printf(" Print only the version number"); + + + printf("\n\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_name); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_name); + printf(" Find and print content from this object name"); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_count); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_count); + printf(" Find a specific occurrence of the object"); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_total); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_total); + printf(" Print the total number of objects in this file"); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_object); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_object); + printf(" Print the object instead of the content"); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_select); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_select); + printf(" Select a specific content to print, default is 0"); + + + printf("\n\n"); + fl_print_color(f_standard_output, data.context.important, data.context.reset, " Usage: "); + + printf("\n "); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, fss_extended_read_name); + + printf(" "); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, "["); + + printf(" options "); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, "]"); + + printf(" "); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, "["); + + printf(" filename(s) "); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, "]"); + + + printf("\n\n"); + + return f_none; + } +#endif // _di_fss_extended_read_print_help_ + +#ifndef _di_fss_extended_read_main_ + f_return_status fss_extended_read_main(const f_s_int argc, const f_string argv[], fss_extended_read_data *data){ + f_status status = f_status_initialize; + f_status allocation_status = f_status_initialize; + + status = fl_process_parameters(argc, argv, data->parameters, fss_extended_read_total_parameters, &data->remaining); + + // load colors when not told to show no colors + if (data->parameters[fss_extended_read_parameter_no_color].result == f_console_result_none){ + fll_new_color_context(allocation_status, data->context); + + if (allocation_status == f_none){ + fll_colors_load_context(&data->context, data->parameters[fss_extended_read_parameter_light].result == f_console_result_found); + } else { + fprintf(f_standard_error, "Critical Error: unable to allocate memory\n"); + fss_extended_read_delete_data(data); + return allocation_status; + } + } + + if (status != f_none){ + if (status == f_no_data){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: One of the parameters you passed requires an additional parameter that you did not pass."); + // TODO: there is a way to identify which parameter is incorrect + // to do this, one must look for any "has_additional" and then see if the "additional" location is set to 0 + // nothing can be 0 as that represents the program name, unless argv[] is improperly created + } else if (f_macro_test_for_allocation_errors(status)){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "CRITICAL ERROR: unable to allocate memory"); + } else if (status == f_invalid_parameter){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling fl_process_parameters()"); + } else { + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fl_process_parameters()", status); + } + + fss_extended_read_delete_data(data); + return status; + } + + // execute parameter results + if (data->parameters[fss_extended_read_parameter_help].result == f_console_result_found){ + fss_extended_read_print_help(*data); + } else if (data->parameters[fss_extended_read_parameter_version].result == f_console_result_found){ + fss_extended_read_print_version(*data); + } else if (data->remaining.used > 0){ + f_string_length counter = f_string_length_initialize; + f_string_length current = f_string_length_initialize; + f_string_length target = f_string_length_initialize; + f_string_length found = f_string_length_initialize; + f_string_length select = f_string_length_initialize; + f_string_length original_size = data->file_position.total_elements; + + if (data->parameters[fss_extended_read_parameter_count].result == f_console_result_additional){ + target = (f_string_length) atoll(argv[data->parameters[fss_extended_read_parameter_count].additional]); + } + + if (data->parameters[fss_extended_read_parameter_select].result == f_console_result_additional){ + select = (f_string_length) atoll(argv[data->parameters[fss_extended_read_parameter_select].additional]); + } + + for (; counter < data->remaining.used; counter++){ + f_file file = f_file_initialize; + + status = f_file_open(&file, argv[data->remaining.array[counter]]); + + data->file_position.total_elements = original_size; + + if (status != f_none){ + if (status == f_invalid_parameter){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling f_file_open()"); + } else if (status == f_file_not_found){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Unable to find the file '%s'", argv[data->remaining.array[counter]]); + } else if (status == f_file_open_error){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Unable to open the file '%s'", argv[data->remaining.array[counter]]); + } else if (status == f_file_descriptor_error){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: File descriptor error while trying to open the file '%s'", argv[data->remaining.array[counter]]); + } else { + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling f_file_open()", status); + } + + fss_extended_read_delete_data(data); + return status; + } + + // TODO: this file size set functionality might be turned into an fl_file (or f_file) function + if (data->file_position.total_elements == 0){ + fseek(file.file, 0, SEEK_END); + + data->file_position.total_elements = ftell(file.file); + + // skip past empty files + if (data->file_position.total_elements == 0){ + f_file_close(&file); + continue; + } + + fseek(file.file, 0, SEEK_SET); + } + + status = fl_file_read(file, data->file_position, &data->buffer); + + f_file_close(&file); + + if (status != f_none && status != f_none_on_eof && status != f_none_on_eos){ + if (status == f_invalid_parameter){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling fl_file_read()"); + } else if (status == f_overflow){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Integer overflow while trying to buffer the file '%s'", argv[data->remaining.array[counter]]); + } else if (status == f_file_not_open){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: The file '%s' is no longer open", argv[data->remaining.array[counter]]); + } else if (status == f_file_seek_error){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: A seek error occurred while accessing the file '%s'", argv[data->remaining.array[counter]]); + } else if (status == f_file_read_error){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: A read error occurred while accessing the file '%s'", argv[data->remaining.array[counter]]); + } else if (f_macro_test_for_allocation_errors(status)){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "CRITICAL ERROR: unable to allocate memory"); + } else { + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fl_file_read()", status); + } + + fss_extended_read_delete_data(data); + return status; + } + + { + f_string_location input = f_string_location_initialize; + + input.stop = data->buffer.used - 1; + + status = fll_fss_extended_read(&data->buffer, &input, &data->objects, &data->contents); + } + + if (status != f_none && status != f_none_on_eos && status != f_none_on_stop && status != fl_fss_found_object_no_content){ + if (status == f_invalid_parameter){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling fll_fss_extended_read() for the file '%s'", argv[data->remaining.array[counter]]); + + fss_extended_read_delete_data(data); + return status; + } else if (status == f_no_data_on_eos || status == f_no_data || status == f_no_data_on_stop || status == f_no_data_on_eof){ + // not an error in this case + } else if (f_macro_test_for_allocation_errors(status)){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "CRITICAL ERROR: unable to allocate memory"); + + fss_extended_read_delete_data(data); + return status; + } else { + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fll_fss_extended_read() for the file '%s'", status, argv[data->remaining.array[counter]]); + } + + // clear buffers, then attempt the next file + f_delete_fss_contents(allocation_status, data->contents); + f_delete_fss_objects(allocation_status, data->objects); + f_delete_dynamic_string(allocation_status, data->buffer); + + continue; + } + + // now that all of the files have been read, process the objects and contents + if (data->parameters[fss_extended_read_parameter_total].result == f_console_result_found){ + fprintf(f_standard_output, "%u\n", (unsigned int) data->objects.used); + } else { + current = 0; + + if (data->parameters[fss_extended_read_parameter_name].result == f_console_result_none){ + if (data->parameters[fss_extended_read_parameter_object].result == f_console_result_none){ + for (; current < data->objects.used; current++){ + if (data->parameters[fss_extended_read_parameter_count].result == f_console_result_none || (data->parameters[fss_extended_read_parameter_count].result == f_console_result_additional && found == target)){ + if (data->contents.array[current].used > select){ + f_print_partial_dynamic_string(f_standard_output, data->buffer, data->contents.array[current].array[select]); + fprintf(f_standard_output, "\n"); + } else { + // for all objects with no data, print a newline + fprintf(f_standard_output, "\n"); + } + } + + if (data->parameters[fss_extended_read_parameter_count].result == f_console_result_additional){ + if (found == target){ + break; + } else { + found++; + } + } + } // for + } else { + for (; current < data->objects.used; current++){ + if (data->parameters[fss_extended_read_parameter_count].result == f_console_result_none || (data->parameters[fss_extended_read_parameter_count].result == f_console_result_additional && found == target)){ + f_print_partial_dynamic_string(f_standard_output, data->buffer, data->objects.array[current]); + fprintf(f_standard_output, "\n"); + } + + if (data->parameters[fss_extended_read_parameter_count].result == f_console_result_additional){ + if (found == target){ + break; + } else { + found++; + } + } + } // for + } + } else { + current = 0; + + f_string_length name_length = f_string_length_initialize; + f_string_length argv_length = f_string_length_initialize; + + if (data->parameters[fss_extended_read_parameter_name].result == f_console_result_additional){ + argv_length = strlen(argv[data->parameters[fss_extended_read_parameter_name].additional]); + + if (data->parameters[fss_extended_read_parameter_object].result == f_console_result_none){ + for (; current < data->objects.used; current++){ + name_length = data->objects.array[current].stop - data->objects.array[current].start + 1; + + if (name_length == argv_length){ + if (fl_compare_strings(data->buffer.string + data->objects.array[current].start, argv[data->parameters[fss_extended_read_parameter_name].additional], name_length, argv_length) == f_equal_to){ + + if (data->parameters[fss_extended_read_parameter_count].result == f_console_result_none || (data->parameters[fss_extended_read_parameter_count].result == f_console_result_additional && found == target)){ + if (data->contents.array[current].used > select){ + f_print_partial_dynamic_string(f_standard_output, data->buffer, data->contents.array[current].array[select]); + fprintf(f_standard_output, "\n"); + } else { + // for all objects with no data, print a newline + fprintf(f_standard_output, "\n"); + } + } + + if (data->parameters[fss_extended_read_parameter_count].result == f_console_result_additional){ + if (found == target){ + break; + } else { + found++; + } + } + } + } + } // for + } else { + // when and because the object parameter is specified, the name parameter refers to the content instead of the object + // therefore, make the search on the content and display the object + for (; current < data->contents.used; current++){ + if (data->contents.array[current].used > select){ + name_length = data->contents.array[current].array[select].stop - data->contents.array[current].array[select].start + 1; + + if (name_length == argv_length){ + if (fl_compare_strings(data->buffer.string + data->contents.array[current].array[select].start, argv[data->parameters[fss_extended_read_parameter_name].additional], name_length, argv_length) == f_equal_to){ + if (data->parameters[fss_extended_read_parameter_count].result == f_console_result_none || (data->parameters[fss_extended_read_parameter_count].result == f_console_result_additional && found == target)){ + f_print_partial_dynamic_string(f_standard_output, data->buffer, data->objects.array[current]); + fprintf(f_standard_output, "\n"); + } + + if (data->parameters[fss_extended_read_parameter_count].result == f_console_result_additional){ + if (found == target){ + break; + } else { + found++; + } + } + } + } + } + } // for + } + } + } + } + + // clear buffers before repeating the loop + f_delete_fss_contents(allocation_status, data->contents); + f_delete_fss_objects(allocation_status, data->objects); + f_delete_dynamic_string(allocation_status, data->buffer); + } // for + } else { + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: you failed to specify one or more files"); + } + + fss_extended_read_delete_data(data); + return status; + } +#endif // _di_fss_extended_read_main_ + +#ifndef _di_fss_extended_read_delete_data_ + f_return_status fss_extended_read_delete_data(fss_extended_read_data *data){ + f_status status = f_status_initialize; + + f_delete_fss_contents(status, data->contents); + f_delete_fss_objects(status, data->objects); + f_delete_dynamic_string(status, data->buffer); + f_delete_string_lengths(status, data->remaining); + + fll_delete_color_context(status, data->context); + + return f_none; + } +#endif // _di_fss_extended_read_delete_data_ + + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_3/fss_extended_read/c/fss_extended_read.h b/level_3/fss_extended_read/c/fss_extended_read.h new file mode 100644 index 0000000..8f0d3a8 --- /dev/null +++ b/level_3/fss_extended_read/c/fss_extended_read.h @@ -0,0 +1,142 @@ +/* FLL - Level 3 + * Project: FSS + * Version: 0.2.0 + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * This is the FSS Basic Read program + * This program utilizes the Featureless Linux Library. + * This program processes files or other input in fss format and stores the results in the fss_extended_read_data + */ +#ifndef _fss_extended_read_h + +// libc includes +#include +#include +#include +#include + +// fll-0 includes +#include +#include +#include +#include +#include + +// fll-1 includes +#include +#include +#include +#include +#include +#include + +// fll-2 includes +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_fss_extended_read_version_ + #define fss_extended_read_major_version "0" + #define fss_extended_read_minor_version "2" + #define fss_extended_read_micro_version "0" + #define fss_extended_read_version fss_extended_read_major_version "." fss_extended_read_minor_version "." fss_extended_read_micro_version +#endif // _di_fss_extended_read_version_ + +#ifndef _di_fss_extended_read_name_ + #define fss_extended_read_name "fss_extended_read" + #define fss_extended_read_name_long "FSS Extended Read" +#endif // _di_fss_extended_read_name_ + +#ifndef _di_fss_extended_read_defines_ + #define f_console_standard_short_name "n" + #define f_console_standard_short_count "c" + #define f_console_standard_short_total "t" + #define f_console_standard_short_object "o" + #define f_console_standard_short_select "s" + + #define f_console_standard_long_name "name" + #define f_console_standard_long_count "count" + #define f_console_standard_long_total "total" + #define f_console_standard_long_object "object" + #define f_console_standard_long_select "select" + + enum { + fss_extended_read_parameter_help, + fss_extended_read_parameter_light, + fss_extended_read_parameter_no_color, + fss_extended_read_parameter_version, + + fss_extended_read_parameter_name, + fss_extended_read_parameter_count, + fss_extended_read_parameter_total, + fss_extended_read_parameter_object, + fss_extended_read_parameter_select, + }; + + #define f_console_parameter_initialize_fss_extended_read \ + { \ + f_console_parameter_initialize(f_console_standard_short_help, f_console_standard_long_help, 0, 0, f_false, f_console_type_normal, 0), \ + f_console_parameter_initialize(f_console_standard_short_light, f_console_standard_long_light, 0, 0, f_false, f_console_type_inverse, 0), \ + f_console_parameter_initialize(f_console_standard_short_no_color, f_console_standard_long_no_color, 0, 0, f_false, f_console_type_inverse, 0), \ + f_console_parameter_initialize(f_console_standard_short_version, f_console_standard_long_version, 0, 0, f_false, f_console_type_normal, 0), \ + f_console_parameter_initialize(f_console_standard_short_name, f_console_standard_long_name, 0, 0, f_true, f_console_type_normal, 0), \ + f_console_parameter_initialize(f_console_standard_short_count, f_console_standard_long_count, 0, 0, f_true, f_console_type_normal, 0), \ + f_console_parameter_initialize(f_console_standard_short_total, f_console_standard_long_total, 0, 0, f_false, f_console_type_normal, 0), \ + f_console_parameter_initialize(f_console_standard_short_object, f_console_standard_long_object, 0, 0, f_false, f_console_type_normal, 0), \ + f_console_parameter_initialize(f_console_standard_short_select, f_console_standard_long_select, 0, 0, f_true, f_console_type_normal, 0), \ + } + + #define fss_extended_read_total_parameters 9 +#endif // _di_fss_extended_read_defines_ + +#ifndef _di_fss_extended_read_data_ + typedef struct { + f_console_parameter parameters[fss_extended_read_total_parameters]; + + f_dynamic_string buffer; + f_fss_objects objects; + f_fss_contents contents; + f_file_position file_position; + f_string_lengths remaining; + + fll_color_context context; + } fss_extended_read_data; + + #define fss_extended_read_data_initialize \ + { \ + f_console_parameter_initialize_fss_extended_read, \ + f_dynamic_string_initialize, \ + f_fss_objects_initialize, \ + f_fss_contents_initialize, \ + f_file_position_initialize, \ + f_string_lengths_initialize, \ + fll_color_context_initialize, \ + } +#endif // _di_fss_extended_read_data_ + +#ifndef _di_fss_extended_read_print_version_ + extern f_return_status fss_extended_read_print_version(const fss_extended_read_data data); +#endif // _di_fss_extended_read_print_version_ + +#ifndef _di_fss_extended_read_print_help_ + extern f_return_status fss_extended_read_print_help(const fss_extended_read_data data); +#endif // _di_fss_extended_read_print_help_ + +#ifndef _di_fss_extended_read_main_ + extern f_return_status fss_extended_read_main(const f_s_int argc, const f_string argv[], fss_extended_read_data *data); +#endif // _di_fss_extended_read_main_ + +#ifndef _di_fss_extended_read_delete_data_ + extern f_return_status fss_extended_read_delete_data(fss_extended_read_data *data); +#endif // _di_fss_extended_read_delete_data_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _fss_extended_read_h diff --git a/level_3/fss_extended_read/c/main.c b/level_3/fss_extended_read/c/main.c new file mode 100644 index 0000000..b427a41 --- /dev/null +++ b/level_3/fss_extended_read/c/main.c @@ -0,0 +1,12 @@ +#include + +int main(const f_s_int argc, const f_string argv[]){ + f_status status = f_status_initialize; + fss_extended_read_data data = fss_extended_read_data_initialize; + + status = fss_extended_read_main(argc, argv, &data); + + if (status == f_none) return 0; + + return status; +}