2025-04-20 10:07:41 +00:00

1239 lines
41 KiB
C

/// _ _ _
/// | | | | | |
/// __ _| |_ __ _ _ __ __| | __ _ _ __ __| |
/// \ \/ / __/ _` | '_ \ / _` |/ _` | '__/ _` |
/// > <| || (_| | | | | (_| | (_| | | | (_| |
/// /_/\_\\__\__,_|_| |_|\__,_|\__,_|_| \__,_|
///
/// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic
///
/// xolatile@chud.cyou - xtandard - Tiny, safe and somewhat sane unity header for what GNU/Linux already provides.
///
/// This program is free software, free as in freedom and as in free beer, you can redistribute it and/or modify it under the terms of the GNU
/// General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version if you wish...
///
/// This program is distributed in the hope that it will be useful, but it is probably not, and without any warranty, without even the implied
/// warranty of merchantability or fitness for a particular purpose, because it is pointless. Please see the GNU (Geenoo) General Public License
/// for more details, if you dare, it is a lot of text that nobody wants to read...
#define _GNU_SOURCE
#include <sys/stat.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <dirent.h>
#define null ((generic *) 0)
#define standard_input (STDIN_FILENO)
#define standard_output (STDOUT_FILENO)
#define standard_error (STDERR_FILENO)
#define file_flag_read (O_RDONLY)
#define file_flag_write (O_WRONLY)
#define file_flag_edit (O_RDWR)
#define file_flag_create (O_CREAT)
#define file_flag_append (O_APPEND)
#define file_flag_truncate (O_TRUNC)
#define file_seek_current (SEEK_CUR)
#define file_seek_set (SEEK_SET)
#define file_seek_end (SEEK_END)
#define pstring_length (256)
#define echo(text) output ((text), sizeof ((text)) - 1)
#define maximum(x, y) (((x) > (y)) ? (x) : (y))
#define minimum(x, y) (((x) < (y)) ? (x) : (y))
#define array_length(array) (sizeof ((array)) / sizeof (* (array)))
typedef void procedure;
typedef void none;
typedef void generic;
typedef char character;
typedef float real;
typedef signed int integer;
typedef unsigned int natural;
typedef float real_32;
typedef double real_64;
typedef signed char integer_8;
typedef signed short integer_16;
typedef signed int integer_32;
typedef signed long integer_64;
typedef unsigned char natural_8;
typedef unsigned short natural_16;
typedef unsigned int natural_32;
typedef unsigned long natural_64;
typedef char pstring [pstring_length];
typedef enum {
false,
true
} boolean;
typedef enum {
log_success, log_warning, log_failure, log_comment,
log_count
} log_enumeration;
typedef enum {
file_type_c_source, file_type_c_header, file_type_ada_sexy_body, file_type_ada_specification,
file_type_cpp_source, file_type_cpp_header, file_type_fortran_90_source, file_type_fortran_90_module,
file_type_pascal_source, file_type_d_source, file_type_go_source, file_type_jai_source,
file_type_assembly, file_type_eax_assembly, file_type_gnu_assembly, file_type_flat_assembly,
file_type_haskell_script, file_type_perl_script, file_type_cube_script, file_type_lua_script,
file_type_shell_script, file_type_python_script, file_type_tcl_script, file_type_forth_source,
file_type_text, file_type_markdown, file_type_html, file_type_glsl,
file_type_xrocessor, file_type_xhla, file_type_xcript, file_type_xocument,
file_type_xiri, file_type_xofya, file_type_xienna, file_type_xenka,
file_type_xiyagi, file_type_xoule, file_type_xikoku, file_type_xdo,
file_type_png_image, file_type_jxl_image, file_type_jpg_image, file_type_tga_image,
file_type_wav_sound, file_type_ogg_sound, file_type_flac_sound, file_type_mp3_sound,
file_type_obj_model, file_type_iqm_model, file_type_md5_model, file_type_ply_model,
file_type_elf_object, file_type_spir_v_bytecode,
file_type_count
} file_type_enumeration;
typedef enum {
effect_normal, effect_bold, effect_italic, effect_undefined_code,
effect_underline, effect_blink, effect_reverse, effect_invisible_text,
effect_count
} effect_enumeration;
typedef enum {
colour_grey, colour_red, colour_green, colour_yellow,
colour_blue, colour_pink, colour_cyan, colour_white,
colour_count
} colour_enumeration;
typedef enum {
character_null, character_start_header, character_start_text, character_end_text,
character_end_transmission, character_enquiry, character_acknowledge, character_bell,
character_backspace, character_tab_horizontal, character_line_feed, character_tab_vertical,
character_form_feed, character_carriage_return, character_shift_out, character_shift_in,
character_data_link_escape, character_device_control_1, character_device_control_2, character_device_control_3,
character_device_control_4, character_not_acknowledge, character_synchronous_idle, character_end_transmission_block,
character_cancel, character_end_medium, character_substitute, character_escape,
character_file_separator, character_group_separator, character_record_separator, character_unit_separator
} character_enumeration;
typedef enum {
cursor_none,
cursor_left, cursor_middle, cursor_right,
cursor_wheel_up, cursor_wheel_down,
cursor_count
} cursor_enumeration;
typedef enum {
signal_none,
signal_a, signal_b, signal_c, signal_d,
signal_e, signal_f, signal_g, signal_h,
signal_i, signal_j, signal_k, signal_l,
signal_m, signal_n, signal_o, signal_p,
signal_q, signal_r, signal_s, signal_t,
signal_u, signal_v, signal_w, signal_x,
signal_y, signal_z, signal_0, signal_1,
signal_2, signal_3, signal_4, signal_5,
signal_6, signal_7, signal_8, signal_9,
signal_escape, signal_tabulator, signal_return, signal_new_line,
signal_slash, signal_backslash, signal_semicolon, signal_backquote,
signal_space, signal_backspace, signal_dot, signal_comma,
signal_cite, signal_caps_lock, signal_minus, signal_equal,
signal_left_bracket, signal_right_bracket, signal_left_control, signal_right_control,
signal_left_shift, signal_right_shift, signal_left_alt, signal_right_alt,
signal_f1, signal_f2, signal_f3, signal_f4,
signal_f5, signal_f6, signal_f7, signal_f8,
signal_f9, signal_f10, signal_f11, signal_f12,
signal_arrow_up, signal_arrow_down, signal_arrow_left, signal_arrow_right,
signal_num_lock, signal_pause_break, signal_insert, signal_home,
signal_page_up, signal_delete, signal_end, signal_page_down,
signal_key_add, signal_key_subtract, signal_key_multiply, signal_key_divide,
signal_key_enter, signal_key_dot, signal_key_0, signal_key_1,
signal_key_2, signal_key_3, signal_key_4, signal_key_5,
signal_key_6, signal_key_7, signal_key_8, signal_key_9,
signal_count
} signal_enumeration;
static character * cursor_name [cursor_count] = {
"---",
"Left button", "Middle button", "Right button",
"Scroll up", "Scroll down"
};
static character * signal_name [signal_count] = {
"---",
"A", "B", "C", "D",
"E", "F", "G", "H",
"I", "J", "K", "L",
"M", "N", "O", "P",
"Q", "R", "S", "T",
"U", "V", "W", "X",
"Y", "Z", "0", "1",
"2", "3", "4", "5",
"6", "7", "8", "9",
"Escape", "Tabulator", "Return", "New line",
"Slash", "Backslash", "Semicolon", "Backquote",
"Space", "Backspace", "Dot", "Comma",
"Cite", "Caps lock", "Minus", "Equal",
"Left bracket", "Right bracket", "Left control", "Right control",
"Left shift", "Right shift", "Left alt", "Right alt",
"F1", "F2", "F3", "F4",
"F5", "F6", "F7", "F8",
"F9", "F10", "F11", "F12",
"Arrow up", "Arrow down", "Arrow left", "Arrow right",
"Num lock", "Pause break", "Insert", "Home",
"Page up", "Delete", "End", "Page down",
"Key add", "Key subtract", "Key multiply", "Key divide",
"Key enter", "Key dot", "Key 0", "Key 1",
"Key 2", "Key 3", "Key 4", "Key 5",
"Key 6", "Key 7", "Key 8", "Key 9"
};
static procedure random_integer_seed_by_time (none) {
srand ((natural) time (null));
}
static integer random_integer (integer from, integer to) {
return (rand () % (to - from + 1) + from);
}
static natural random_natural (natural from, natural to) {
return ((natural) rand () % (to - from + 1) + from);
}
static real random_real (real from, real to) {
return (((real) rand () / (real) RAND_MAX) * (to - from) + from);
}
static procedure input (generic * data, natural_64 size) {
read (standard_input, data, size);
}
static procedure output (generic * data, natural_64 size) {
write (standard_output, data, size);
}
static procedure clean_up (procedure (* procedure_pointer) (none)) {
atexit (procedure_pointer);
}
#ifdef use_fatal_failure
static procedure fatal_failure (boolean condition, character * message) {
if (condition == true) {
echo ("[\x1b[1;31m FATAL \x1b[0m] ");
for (integer index = 0; message [index] != '\0'; ++index) {
output (& message [index], 1);
}
echo ("\n");
exit (log_failure);
}
}
#else
#define fatal_failure(...)
#endif
static procedure execute (character * command) {
integer status = 0;
system (command);
fatal_failure (status != 0, "execute: System returned an error code.");
}
static natural tick_tock (none) {
return ((natural) clock ());
}
static natural_64 nano_time (none) {
struct timespec time = { 0 };
natural_64 result = 0;
clock_gettime (CLOCK_MONOTONIC, & time);
result = 1000000000ul * (natural_64) time.tv_sec + (natural_64) time.tv_nsec;
return (result);
}
static procedure nano_wait (natural_64 time) {
struct timespec wait = {
time / 1000000000,
time % 1000000000
};
while (nanosleep (& wait, null)) continue;
}
static procedure exchange_integer (integer * a, integer * b) { integer c = * a; * a = * b; * b = c; }
static procedure exchange_natural (natural * a, natural * b) { natural c = * a; * a = * b; * b = c; }
static procedure exchange_real (real * a, real * b) { real c = * a; * a = * b; * b = c; }
static procedure clamp_integer (integer * x, integer lower, integer upper) { if (* x < lower) * x = lower; if (* x > upper) * x = upper; }
static procedure clamp_natural (natural * x, natural lower, natural upper) { if (* x < lower) * x = lower; if (* x > upper) * x = upper; }
static procedure clamp_real (real * x, real lower, real upper) { if (* x < lower) * x = lower; if (* x > upper) * x = upper; }
static real normal_r (natural colour) { return ((real) ((colour >> 24) & 0xff) / 255.0f); }
static real normal_g (natural colour) { return ((real) ((colour >> 16) & 0xff) / 255.0f); }
static real normal_b (natural colour) { return ((real) ((colour >> 8) & 0xff) / 255.0f); }
static real normal_a (natural colour) { return ((real) ((colour >> 0) & 0xff) / 255.0f); }
static natural channel_r (natural colour) { return ((colour >> 24) & 0xff); }
static natural channel_g (natural colour) { return ((colour >> 16) & 0xff); }
static natural channel_b (natural colour) { return ((colour >> 8) & 0xff); }
static natural channel_a (natural colour) { return ((colour >> 0) & 0xff); }
static natural colour_channel_reverse (natural colour) {
natural r = channel_r (colour);
natural g = channel_g (colour);
natural b = channel_b (colour);
natural a = channel_a (colour);
return ((a << 24) | (b << 16) | (g << 8) | (r << 0));
}
static natural colour_linear_interpolation (natural colour_a, natural colour_b, real scale) {
if (scale <= 0.0f) {
return (colour_a);
}
if (scale >= 1.0f) {
return (colour_b);
}
natural r = (natural) ((1.0f - scale) * channel_r (colour_a) + scale * channel_r (colour_b));
natural g = (natural) ((1.0f - scale) * channel_g (colour_a) + scale * channel_g (colour_b));
natural b = (natural) ((1.0f - scale) * channel_b (colour_a) + scale * channel_b (colour_b));
natural a = (natural) ((1.0f - scale) * channel_a (colour_a) + scale * channel_a (colour_b));
return ((r << 24) | (g << 16) | (b << 8) | (a << 0));
}
static generic * allocate (natural_64 size) {
character * data = null;
fatal_failure (size <= 0, "allocate: Size is equal or below zero.");
data = calloc (size, sizeof (* data));
fatal_failure (data == null, "allocate: Function 'calloc' returned null pointer.");
return (data);
}
static generic * reallocate (generic * data, natural_64 size) {
fatal_failure (size <= 0, "reallocate: Size is equal or below zero.");
data = realloc (data, size);
fatal_failure (data == null, "reallocate: Function 'realloc' returned null pointer.");
return (data);
}
static generic * deallocate (generic * data) {
fatal_failure (data == null, "deallocate: Data is null pointer.");
free (data);
return (null);
}
static generic * record (none) {
character * buffer = null;
natural_64 offset = 0;
natural_64 memory = 64 * 1024;
buffer = reallocate (buffer, memory);
do {
if ((offset + 1) % memory == 0) {
buffer = reallocate (buffer, ((offset + 1) / memory + 1) * memory);
}
buffer [offset] = '\0';
input (& buffer [offset], sizeof (* buffer));
++offset;
} while (buffer [offset - 1] != '\0');
buffer [offset - 1] = '\0';
return (buffer);
}
static boolean character_compare_array (character c, character * character_array) {
for (natural_64 index = 0; character_array [index] != '\0'; ++index) {
if (c == character_array [index]) {
return (true);
}
}
return (false);
}
static boolean character_is_uppercase (character c) {
return ((c >= 'A') && (c <= 'Z'));
}
static boolean character_is_lowercase (character c) {
return ((c >= 'a') && (c <= 'z'));
}
static boolean character_is_digit (character c) {
return ((c >= '0') && (c <= '9'));
}
static boolean character_is_letter (character c) {
return (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')));
}
static boolean character_is_blank (character c) {
return ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n'));
}
static boolean character_is_symbol (character c) {
return (((c >= '!') && (c <= '/')) || ((c >= ':') && (c <= '@')) || ((c >= '[') && (c <= '`')) || ((c >= '{') && (c <= '~')));
}
static boolean character_is_separator (character c) {
return ((c != '_') && ((character_is_blank (c) == true) || (character_is_symbol (c) == true)));
}
static boolean character_is_identifier (character c) {
return ((c == '_') || (character_is_letter (c) == true) || (character_is_digit (c) == true));
}
static boolean character_is_visible (character c) {
return ((c >= '!') && (c <= '~'));
}
static boolean character_is_invisible (character c) {
return (character_is_visible (c) == false);
}
static character * capitalize (character * string) {
fatal_failure (string == null, "capitalize: String is null pointer.");
string [0] -= (character_is_lowercase (string [0]) == true) ? ' ' : '\0';
return (string);
}
static character * uppercase (character * string) {
fatal_failure (string == null, "uppercase: String is null pointer.");
for (natural index = 0; string [index] != '\0'; ++index) {
string [index] += (character_is_lowercase (string [index]) == true) ? ' ' : '\0';
}
return (string);
}
static character * lowercase (character * string) {
fatal_failure (string == null, "lowercase: String is null pointer.");
for (natural index = 0; string [index] != '\0'; ++index) {
string [index] -= (character_is_uppercase (string [index]) == true) ? ' ' : '\0';
}
return (string);
}
static natural_64 string_length (character * string) {
natural_64 length = 0;
fatal_failure (string == null, "string_length: String is null pointer.");
for (length = 0; string [length] != '\0'; ++length);
return (length);
}
static character * string_nullify (character * destination, natural_64 length) {
fatal_failure (destination == null, "string_reverse_limit: Destination string is null pointer.");
fatal_failure (length <= 0, "string_reverse_limit: Length is equal or below zero.");
for (natural_64 index = 0; index < length; ++index) {
destination [index] = '\0';
}
return (destination);
}
static character * string_reverse_limit (character * destination, natural_64 limit) {
fatal_failure (destination == null, "string_reverse_limit: Destination string is null pointer.");
fatal_failure (limit <= 0, "string_reverse_limit: Limit is equal or below zero.");
for (natural_64 index = 0; index < limit / 2; ++index) {
character temporary = destination [index];
destination [index] = destination [limit - 1 - index];
destination [limit - 1 - index] = temporary;
}
return (destination);
}
static character * string_reverse (character * destination) {
return (string_reverse_limit (destination, string_length (destination)));
}
static boolean string_compare_limit (character * string_a, character * string_b, natural_64 limit) {
fatal_failure (string_a == null, "string_compare_limit: First source string is null pointer.");
fatal_failure (string_b == null, "string_compare_limit: Second source string is null pointer.");
fatal_failure (limit <= 0, "string_compare_limit: Limit is equal or below zero.");
for (natural_64 index = 0; index < limit; ++index) {
if (string_a [index] != string_b [index]) {
return (false);
}
}
return (true);
}
static boolean string_compare (character * string_a, character * string_b) {
return (string_compare_limit (string_a, string_b, string_length (string_a) + 1));
}
static character * string_copy_limit (character * destination, character * source, natural_64 limit) {
fatal_failure (destination == null, "string_copy_limit: Destination string is null pointer.");
fatal_failure (source == null, "string_copy_limit: Source string is null pointer.");
fatal_failure (limit <= 0, "string_copy_limit: Limit is equal or below zero.");
for (natural_64 index = 0; index < limit; ++index) {
destination [index] = source [index];
}
return (destination);
}
static character * string_copy (character * destination, character * source) {
return (string_copy_limit (destination, source, string_length (source) + 1));
}
static character * string_concatenate_limit (character * destination, character * source, natural_64 limit) {
natural_64 offset = string_length (destination);
fatal_failure (destination == null, "string_concatenate_limit: Destination string is null pointer.");
fatal_failure (source == null, "string_concatenate_limit: Source string is null pointer.");
fatal_failure (limit <= 0, "string_concatenate_limit: Limit is equal or below zero.");
for (natural_64 index = 0; index < limit; ++index) {
destination [offset + index] = source [index];
}
return (destination);
}
static character * string_concatenate (character * destination, character * source) {
return (string_concatenate_limit (destination, source, string_length (source) + 1));
}
static character * string_duplicate (character * source) {
character * duplicate = allocate ((string_length (source) + 1) * sizeof (* duplicate));
string_copy (duplicate, source);
return (duplicate);
}
static character * string_duplicate_limit (character * source, natural limit) {
character * duplicate = allocate ((limit + 1) * sizeof (* duplicate));
string_copy_limit (duplicate, source, limit);
return (duplicate);
}
static character * string_align_left (character * destination, natural_64 amount, character with) {
for (natural_64 offset = string_length (destination); offset < amount; ++offset) {
destination [offset] = with;
}
destination [amount] = '\0';
return (destination);
}
static character * string_remove_extension (character * destination) {
natural_64 length = string_length (destination);
for (--length; destination [length] != '.'; --length);
destination [length] = '\0';
return (destination);
}
static procedure memory_nullify (generic * memory, natural_64 size) {
character * cast = (character *) memory;
fatal_failure (memory == null, "memory_nullify: Memory is null pointer.");
for (natural_64 offset = 0; offset < size; ++offset) {
cast [offset] = (character) 0;
}
}
static integer memory_compare (generic * memory_0, generic * memory_1, natural_64 size) {
character * cast_0 = (character *) memory_0;
character * cast_1 = (character *) memory_1;
fatal_failure (memory_0 == null, "memory_compare: Memory is null pointer.");
fatal_failure (memory_1 == null, "memory_compare: Source is null pointer.");
for (natural_64 offset = 0; offset < size; ++offset) {
if (cast_0 [offset] != cast_1 [offset]) {
return (false);
}
}
return (true);
}
static procedure memory_copy (generic * destination, generic * source, natural_64 size) {
character * cast_0 = ( character *) destination;
character * cast_1 = (character *) source;
fatal_failure (destination == null, "memory_copy: Destination is null pointer.");
fatal_failure (source == null, "memory_copy: Source is null pointer.");
for (natural_64 offset = 0; offset < size; ++offset) {
cast_0 [offset] = cast_1 [offset];
}
}
static procedure echo_clear (none) {
echo ("\033[2J\033[H");
}
static procedure echo_colour (colour_enumeration colour, effect_enumeration effect) {
character format [8] = "\033[ ;3 m";
format [2] = (character) (effect % effect_count) + '0';
format [5] = (character) (colour % colour_count) + '0';
echo (format);
}
static procedure echo_cancel (none) {
echo ("\033[0m");
}
static procedure show_cursor (boolean show) {
if (show == true) {
echo ("\033[?25h");
} else {
echo ("\033[?25l");
}
}
static integer file_open (character * path, integer mode) {
fatal_failure (path == null, "file_open: File path is null pointer.");
return (open (path, mode, 0777));
}
static integer file_close (integer file) {
fatal_failure (file == -1, "file_close: Invalid file descriptor.");
close (file);
return (-1);
}
static procedure file_read (integer file, generic * data, natural_64 size) {
fatal_failure (file <= -1, "file_read: File descriptor is closed or invalid.");
fatal_failure (data == null, "file_read: Data is null pointer.");
fatal_failure (size == 0, "file_read: Size is zero.");
read (file, data, size);
}
static procedure file_write (integer file, generic * data, natural_64 size) {
fatal_failure (file <= -1, "file_write: File descriptor is closed or invalid.");
fatal_failure (data == null, "file_write: Data is null pointer.");
fatal_failure (size == 0, "file_write: Size is zero.");
write (file, data, size);
}
static procedure file_echo (integer file, character * data) {
file_write (file, data, string_length (data));
}
static natural_64 file_seek (integer file, integer whence) {
fatal_failure (file == -1, "file_seek: Invalid file descriptor.");
return ((natural_64) lseek (file, 0, whence));
}
static natural_64 file_size (character * path) {
struct stat data = { 0 };
fatal_failure (path == null, "file_size: File path is null pointer.");
lstat (path, & data);
return ((natural_64) data.st_size);
}
static boolean file_exists (character * path) {
fatal_failure (path == null, "file_record: File path is null pointer.");
return ((access (path, F_OK) == 0) ? true : false);
}
static file_type_enumeration file_type (character * path) {
character * extensions [file_type_count] = {
".c", ".h", ".adb", ".ads", ".cpp", ".hpp", ".f90", ".mod",
".pas", ".d", ".go", ".jai", ".asm", ".eax", ".gas", ".fasm",
".hs", ".el", ".cfg", ".lua", ".sh", ".py", ".tcl", ".4th",
".txt", ".md", ".html", ".glsl", ".x", ".xhla", ".xs", ".xd",
".xiri", ".xofya", ".xienna", ".xenka", ".xiyagi", ".xoule", ".xikoku", ".xdo",
".png", ".jxl", ".jpg", ".tga", ".wav", ".ogg", ".flac", ".mp3",
".obj", ".iqm", ".md5", ".ply", ".o", ".spv"
};
natural cut_at = 0;
fatal_failure ((path == null) || (* path == '\0'), "file_type: File path is null pointer.");
for (cut_at = string_length (path) - 1; cut_at != 0; --cut_at) {
if (path [cut_at] == '.') break;
}
for (file_type_enumeration type = 0; type != file_type_count; ++type) {
if (string_compare (& path [cut_at], extensions [type])) {
return (type);
}
}
return (file_type_count);
}
static procedure file_remove (character * path) {
unlink (path);
}
static generic * file_record (character * path) {
integer file = -1;
natural_64 size = 0;
character * data = null;
fatal_failure (path == null, "file_record: File path is null pointer.");
file = file_open (path, file_flag_read);
size = file_size (path);
data = allocate (size);
file_read (file, data, size);
file = file_close (file);
return (data);
}
static character * file_import (character * path) {
integer file = -1;
natural_64 size = 0;
character * data = null;
fatal_failure (path == null, "file_import: File path is null pointer.");
file = file_open (path, file_flag_edit);
size = file_size (path) + 1;
data = allocate (size);
file_read (file, data, size - 1);
data [size - 1] = '\0';
file = file_close (file);
return (data);
}
static procedure file_export (character * path, character * data) {
integer file = -1;
fatal_failure (path == null, "file_export: File path is null pointer.");
fatal_failure (data == null, "file_export: Data is null pointer.");
file = file_open (path, file_flag_write | file_flag_create | file_flag_truncate);
file_write (file, data, string_length (data));
file = file_close (file);
}
static generic * folder_open (character * path) {
DIR * folder = null;
fatal_failure (path == null, "folder_open: Folder path is null pointer.");
folder = opendir (path);
return ((generic *) folder);
}
static character * folder_read (generic * handle) {
struct dirent * file = null;
DIR * folder = (DIR *) handle;
fatal_failure (handle == null, "folder_read: Folder handle is null pointer.");
file = readdir (folder);
if (file == null) {
return (null);
} else {
return (file->d_name);
}
}
static generic * folder_close (generic * handle) {
DIR * folder = (DIR *) handle;
fatal_failure (handle == null, "folder_read: Folder handle is null pointer.");
closedir (folder);
return (null);
}
static character * * folder_create_path_list (character * folder, natural * path_count, boolean sort) {
procedure * handle = null;
character * * path_array = 0;
(none) sort;
fatal_failure (folder == null, "folder_create_path_list: Folder handle is null pointer.");
fatal_failure (path_count == null, "folder_create_path_list: Path count address is null pointer.");
handle = folder_open (folder);
for (character * path = folder_read (handle); path != null; path = folder_read (handle)) {
if (path [0] != '.') {
(* path_count) += 1;
path_array = reallocate (path_array, (* path_count) * sizeof (* path_array));
path_array [(* path_count) - 1] = allocate ((string_length (path) + 1) * sizeof (* * path_array));
string_copy (path_array [(* path_count) - 1], path);
}
}
handle = folder_close (handle);
return (path_array);
}
static character * * folder_remove_path_list (character * * path_array, natural path_count) {
for (natural index = 0; index < path_count; ++index) {
path_array [index] = deallocate (path_array [index]);
}
return (deallocate (path_array));
}
static character * configuration_format (character * path) {
static character buffer [512] = "";
string_copy (buffer, getenv ("HOME"));
string_concatenate (buffer, "/.config/xolatile/");
string_concatenate (buffer, path);
return (buffer);
}
static boolean configuration_exists (character * path) {
return (file_exists (configuration_format (path)));
}
static procedure configuration_remove (character * path) {
file_remove (configuration_format (path));
}
static character * configuration_import (character * path) {
return (file_import (configuration_format (path)));
}
static procedure configuration_export (character * path, character * data) {
file_export (configuration_format (path), data);
}
static boolean argument_compare (character * argument, character * short_option, character * long_option) {
return ((string_compare (argument, short_option) == true) || (string_compare (argument, long_option) == true));
}
static natural string_full_width (character * string, natural tab_width) {
natural width = 0;
natural count = 0;
do {
if (* string == '\t') {
count += tab_width;
} else if (* string == '\n') {
width = (++count > width) ? count : width;
count = 0;
} else {
++count;
}
} while (* (++string) != '\0');
return (width - 1);
}
static natural string_full_height (character * string) {
natural height = 0;
do {
if (* string == '\n') {
++height;
}
} while (* (++string) != '\0');
return (height + 1);
}
static natural string_limit_to_number (character * string, natural limit) {
natural number = 0;
for (natural index = 0; (string [index] != '\0') && (index < limit); ++index) {
number *= 10;
number += (natural) (string [index] - '0');
}
return (number);
}
static natural string_to_number (character * string) {
return (string_limit_to_number (string, string_length (string)));
}
static character * number_to_string (integer number) {
static character string [34] = "";
natural index = 0;
boolean sign = false;
string_nullify (string, sizeof (string));
if (number == 0) {
string [0] = '0';
string [1] = '\0';
return (string);
}
if (number < 0) {
number *= -1;
sign = true;
} else {
sign = false;
}
for (index = 0; (number != 0) && (index < (natural) sizeof (string) - 1); ++index) {
string [index] = (character) (number % 10) + '0';
number /= 10;
}
if (sign == true) {
string [index] = '-';
++index;
}
string [index] = '\0';
string_reverse (string);
return (string);
}
static character * format_to_string (integer number, boolean sign, natural base, natural_64 amount, character with) {
static character string [36];
integer i;
string_nullify (string, sizeof (string));
if (number == 0) {
string [0] = '0';
string [1] = '\0';
string_align_left (string, amount, with);
return (string);
}
if (number < 0) {
number *= -1;
}
for (i = (string [0] == '-'); number != 0; ++i) {
string [i] = "0123456789ABCDEF" [number % base];
number /= base;
}
if (sign == true) {
string [i] = '-';
++i;
}
string [i] = '\0';
string_reverse (string);
string_align_left (string, amount, with);
return (string);
}
static character * format (character * base, ...) {
static character string [1024];
va_list list;
string_nullify (string, 1024);
va_start (list, base);
for (; * base != character_null; ++base) {
switch (* base) {
case ('%'): {
++base;
switch (* base) {
case ('%'): string_concatenate (string, "%"); break;
case ('i'): string_concatenate (string, number_to_string (va_arg (list, integer))); break;
case ('s'): string_concatenate (string, va_arg (list, character *)); break;
default: string_concatenate (string, "?"); break;
}
} break;
default: {
string_concatenate_limit (string, base, 1);
} break;
}
}
va_end (list);
return (string);
}
static procedure print (character * format, ...) {
va_list list;
va_start (list, format);
for (; * format != character_null; ++format) {
switch (* format) {
case ('%'): {
++format;
switch (* format) {
case ('%'): {
output ("%", 1);
} break;
case ('i'): {
character * string = number_to_string (va_arg (list, integer));
output (string, string_length (string));
} break;
case ('f'): {
real data = (real) va_arg (list, real_64);
character * upper = number_to_string ((integer) data);
character * lower = number_to_string ((integer) (data * 1000.0f) % 1000);
output (upper, string_length (upper));
output (".", 1);
output (lower, string_length (lower));
} break;
case ('t'): {
integer data = (va_arg (list, integer));
echo_colour ((data == true) ? colour_green : colour_red, effect_normal);
output ((data == true) ? "+" : "-", 1);
echo_cancel ();
} break;
case ('b'): {
integer data = (va_arg (list, integer));
output ((data == true) ? "true" : "false", (data == true) ? 4 : 5);
} break;
case ('c'): {
character data = (character) va_arg (list, integer);
output (& data, 1);
} break;
case ('s'): {
character * data = va_arg (list, character *);
output (data, string_length (data));
} break;
default: {
output ("?", 1);
} break;
}
} break;
case ('/'): {
++format;
switch (* format) {
case ('/'): echo ("/"); break;
case ('s'): echo ("[\x1b[1;32mSuccess\x1b[0m]"); break;
case ('f'): echo ("[\x1b[1;31mFailure\x1b[0m]"); break;
case ('w'): echo ("[\x1b[1;33mWarning\x1b[0m]"); break;
case ('c'): echo ("[\x1b[1;30mComment\x1b[0m]"); break;
case ('A'): echo ("\x1b[0m"); break;
case ('B'): echo ("\x1b[1m"); break;
case ('C'): echo ("\x1b[2m"); break;
case ('D'): echo ("\x1b[3m"); break;
case ('E'): echo ("\x1b[4m"); break;
case ('F'): echo ("\x1b[5m"); break;
case ('G'): echo ("\x1b[6m"); break;
case ('H'): echo ("\x1b[7m"); break;
case ('0'): echo ("\x1b[30m"); break;
case ('1'): echo ("\x1b[31m"); break;
case ('2'): echo ("\x1b[32m"); break;
case ('3'): echo ("\x1b[33m"); break;
case ('4'): echo ("\x1b[34m"); break;
case ('5'): echo ("\x1b[35m"); break;
case ('6'): echo ("\x1b[36m"); break;
case ('7'): echo ("\x1b[37m"); break;
case ('-'): echo ("\x1b[0m"); break;
default: echo ("?"); break;
}
} break;
default: {
output (format, 1);
} break;
}
}
va_end (list);
}
static procedure conditional_print (boolean condition, character * format, ...) {
va_list list;
if (condition == false) return;
va_start (list, format);
for (; * format != character_null; ++format) {
switch (* format) {
case ('%'): {
++format;
switch (* format) {
case ('%'): {
output ("%", 1);
} break;
case ('i'): {
character * string = number_to_string (va_arg (list, integer));
output (string, string_length (string));
} break;
case ('f'): {
real data = (real) va_arg (list, real_64);
character * upper = number_to_string ((integer) data);
character * lower = number_to_string ((integer) (data * 1000.0f) % 1000);
output (upper, string_length (upper));
output (".", 1);
output (lower, string_length (lower));
} break;
case ('t'): {
integer data = (va_arg (list, integer));
echo_colour ((data == true) ? colour_green : colour_red, effect_normal);
output ((data == true) ? "+" : "-", 1);
echo_cancel ();
} break;
case ('b'): {
integer data = (va_arg (list, integer));
output ((data == true) ? "true" : "false", (data == true) ? 4 : 5);
} break;
case ('c'): {
character data = (character) va_arg (list, integer);
output (& data, 1);
} break;
case ('s'): {
character * data = va_arg (list, character *);
output (data, string_length (data));
} break;
default: {
output ("?", 1);
} break;
}
} break;
case ('/'): {
++format;
switch (* format) {
case ('/'): echo ("/"); break;
case ('s'): echo ("[\x1b[1;32mSuccess\x1b[0m]"); break;
case ('f'): echo ("[\x1b[1;31mFailure\x1b[0m]"); break;
case ('w'): echo ("[\x1b[1;33mWarning\x1b[0m]"); break;
case ('c'): echo ("[\x1b[1;30mComment\x1b[0m]"); break;
case ('A'): echo ("\x1b[0m"); break;
case ('B'): echo ("\x1b[1m"); break;
case ('C'): echo ("\x1b[2m"); break;
case ('D'): echo ("\x1b[3m"); break;
case ('E'): echo ("\x1b[4m"); break;
case ('F'): echo ("\x1b[5m"); break;
case ('G'): echo ("\x1b[6m"); break;
case ('H'): echo ("\x1b[7m"); break;
case ('0'): echo ("\x1b[30m"); break;
case ('1'): echo ("\x1b[31m"); break;
case ('2'): echo ("\x1b[32m"); break;
case ('3'): echo ("\x1b[33m"); break;
case ('4'): echo ("\x1b[34m"); break;
case ('5'): echo ("\x1b[35m"); break;
case ('6'): echo ("\x1b[36m"); break;
case ('7'): echo ("\x1b[37m"); break;
case ('-'): echo ("\x1b[0m"); break;
default: echo ("?"); break;
}
} break;
default: {
output (format, 1);
} break;
}
}
va_end (list);
}
#ifdef use_mathematics
#include <math.h>
#define pi (3.14159265f)
static real sign (real x) { return ((x > 0.0f) ? + 1.0f : - 1.0f); }
static real binary_sign (natural x) { return ((x > 0) ? + 1.0f : - 1.0f); }
static real square_root (real x) { return (sqrtf (x)); }
static real cube_root (real x) { return (cbrtf (x)); }
static real sine (real x) { return (sinf (x)); }
static real cosine (real x) { return (cosf (x)); }
static real tangent (real x) { return (tanf (x)); }
static real arc_sine (real x) { return (asinf (x)); }
static real arc_cosine (real x) { return (acosf (x)); }
static real arc_tangent (real x) { return (atanf (x)); }
static real cosecant (real x) { return (1.0f / sinf (x)); }
static real secant (real x) { return (1.0f / cosf (x)); }
static real cotangent (real x) { return (1.0f / tanf (x)); }
#endif