xtandard/xtandard.h
2024-12-31 09:00:35 -05:00

933 lines
31 KiB
C
Executable File

// _ _ _
// | | | | | |
// __ _| |_ __ _ _ __ __| | __ _ _ __ __| |
// \ \/ / __/ _` | '_ \ / _` |/ _` | '__/ _` |
// > <| || (_| | | | | (_| | (_| | | | (_| |
// /_/\_\\__\__,_|_| |_|\__,_|\__,_|_| \__,_|
//
// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic
//
// xolatile@proton.me - 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>
#define null ((void *) 0)
#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 echo(text) output ((text), sizeof ((text)) - 1)
#define maximum(x, y) (((x) < (y)) ? (x) : (y))
#define minimum(x, y) (((x) > (y)) ? (x) : (y))
#define limit(value, from, to) value = ((value) <= (from)) ? (from) : (value); value = ((value) >= (to)) ? (to) : (value)
#define randomize(from, to) (rand () % ((to) - (from) + 1) + (from))
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef enum {
false,
true
} bool;
typedef enum {
log_error = -1,
log_success, log_warning, log_failure, log_comment,
log_count
} log_enumeration;
typedef enum {
file_type_error = -1,
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, file_type_pascal,
file_type_assembly, file_type_eax_assembly, file_type_gnu_assembly, file_type_flat_assembly,
file_type_text, file_type_markdown, file_type_html, file_type_glsl,
file_type_shell, file_type_python, file_type_tcl, file_type_forth,
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_count
} file_type_enumeration;
typedef enum {
effect_error = -1,
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_error = -1,
colour_grey, colour_red, colour_green, colour_yellow,
colour_blue, colour_pink, colour_cyan, colour_white,
colour_count
} colour_enumeration;
typedef enum {
character_error = -1,
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_error = -1,
cursor_none, cursor_left, cursor_middle, cursor_right,
cursor_wheel_up, cursor_wheel_down,
cursor_count
} cursor_enumeration;
typedef enum {
signal_error = -1,
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 const char * 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 void input (void * data, ulong size) {
read (STDIN_FILENO, data, size);
}
static void output (const void * data, ulong size) {
write (STDOUT_FILENO, data, size);
}
static void clean_up (void (* procedure) (void)) {
atexit (procedure);
}
static void execute (const char * command) {
system (command);
}
static void fatal_failure (bool condition, const char * message) {
if (condition == true) {
echo ("[\x1b[1;31m FATAL \x1b[0m] ");
for (int index = 0; message [index] != '\0'; ++index) {
output (& message [index], 1);
}
echo ("\n");
exit (log_failure);
}
}
static uint tick_tock (void) {
return ((uint) clock ());
}
static ulong nano_time (void) {
struct timespec time = { 0 };
ulong result = 0;
clock_gettime (CLOCK_MONOTONIC, & time);
result = 1000000000ul * (ulong) time.tv_sec + (ulong) time.tv_nsec;
return (result);
}
static void nano_wait (ulong time) {
struct timespec wait = {
time / 1000000000,
time % 1000000000
};
while (nanosleep (& wait, null)) continue;
}
static void * allocate (ulong size) {
char * 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 void * reallocate (void * data, ulong 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 void * deallocate (void * data) {
fatal_failure (data == null, "deallocate: Data is null pointer.");
free (data);
return (null);
}
static void * record (void) {
char * buffer = null;
ulong offset = 0;
ulong 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 bool character_compare_array (char character, const char * character_array) {
for (ulong index = 0; character_array [index] != '\0'; ++index) {
if (character == character_array [index]) {
return (true);
}
}
return (false);
}
static bool character_is_uppercase (char character) {
return ((character >= 'A') && (character <= 'Z'));
}
static bool character_is_lowercase (char character) {
return ((character >= 'a') && (character <= 'z'));
}
static bool character_is_digit (char character) {
return ((character >= '0') && (character <= '9'));
}
static bool character_is_letter (char character) {
return (((character >= 'A') && (character <= 'Z')) || ((character >= 'a') && (character <= 'z')));
}
static bool character_is_blank (char character) {
return ((character == ' ') || (character == '\t') || (character == '\r') || (character == '\n'));
}
static bool character_is_symbol (char character) {
return (((character >= '!') && (character <= '/')) || ((character >= ':') && (character <= '@'))
|| ((character >= '[') && (character <= '`')) || ((character >= '{') && (character <= '~')));
}
static bool character_is_separator (char character) {
return ((character != '_') && ((character_is_blank (character) == true) || (character_is_symbol (character) == true)));
}
static bool character_is_identifier (char character) {
return ((character == '_') || (character_is_letter (character) == true) || (character_is_digit (character) == true));
}
static bool character_is_visible (char character) {
return ((character >= '!') && (character <= '~'));
}
static ulong string_length (const char * string) {
ulong length = 0;
fatal_failure (string == null, "string_length: String is null pointer.");
for (length = 0; string [length] != '\0'; ++length);
return (length);
}
static char * string_nullify (char * string, ulong length) {
fatal_failure (string == null, "string_nullify: String is null pointer.");
fatal_failure (length <= 0, "string_nullify: Length is equal or below zero.");
for (ulong index = 0; index < length; ++index) {
string [index] = '\0';
}
return (string);
}
static char * string_reverse_limit (char * string, ulong limit) {
fatal_failure (string == null, "string_reverse_limit: String is null pointer.");
fatal_failure (limit <= 0, "string_reverse_limit: Limit is equal or below zero.");
for (ulong index = 0; index < limit / 2; ++index) {
char temporary = string [index];
string [index] = string [limit - 1 - index];
string [limit - 1 - index] = temporary;
}
return (string);
}
static char * string_reverse (char * string) {
return (string_reverse_limit (string, string_length (string)));
}
static bool string_compare_limit (const char * string_a, const char * string_b, ulong 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 (ulong index = 0; index < limit; ++index) {
if (string_a [index] != string_b [index]) {
return (false);
}
}
return (true);
}
static bool string_compare (const char * string_a, const char * string_b) {
return (string_compare_limit (string_a, string_b, string_length (string_a) + 1));
}
static char * string_copy_limit (char * destination, const char * source, ulong 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 (ulong index = 0; index < limit; ++index) {
destination [index] = source [index];
}
return (destination);
}
static char * string_copy (char * destination, const char * source) {
return (string_copy_limit (destination, source, string_length (source) + 1));
}
static char * string_concatenate_limit (char * destination, const char * source, ulong limit) {
ulong 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 (ulong index = 0; index < limit; ++index) {
destination [offset + index] = source [index];
}
return (destination);
}
static char * string_concatenate (char * destination, const char * source) {
return (string_concatenate_limit (destination, source, string_length (source) + 1));
}
///////////////////////////////////////////
///////////////////////////////////////////
///////////////////////////////////////////
///////////////////////////////////////////
///////////////////////////////////////////
///////////////////////////////////////////
///////////////////////////////////////////
///////////////////////////////////////////
///////////////////////////////////////////
///////////////////////////////////////////
///////////////////////////////////////////
///////////////////////////////////////////
static char * string_realign (char * string, ulong amount, char character) {
ulong length = string_length (string);
for (ulong offset = 0; offset < length; ++offset) {
string [amount - offset - 1] = string [length - offset - 1];
}
for (ulong offset = 0; offset < amount - length; ++offset) {
string [offset] = character;
}
string [amount] = '\0';
return (string);
}
static void memory_nullify (void * memory, ulong size) {
char * cast = (char *) memory;
fatal_failure (memory == null, "memory_nullify: Memory is null pointer.");
for (ulong offset = 0; offset < size; ++offset) {
cast [offset] = (char) 0;
}
}
static int memory_compare (void * memory_0, const void * memory_1, ulong size) {
char * cast_0 = ( char *) memory_0;
const char * cast_1 = (const char *) 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 (ulong offset = 0; offset < size; ++offset) {
if (cast_0 [offset] != cast_1 [offset]) {
return (false);
}
}
return (true);
}
static void memory_copy (void * destination, const void * source, ulong size) {
char * cast_0 = ( char *) destination;
const char * cast_1 = (const char *) source;
fatal_failure (destination == null, "memory_copy: Destination is null pointer.");
fatal_failure (source == null, "memory_copy: Source is null pointer.");
for (ulong offset = 0; offset < size; ++offset) {
cast_0 [offset] = cast_1 [offset];
}
}
static void terminal_clear (void) {
echo ("\033[2J\033[H");
}
static void terminal_colour (colour_enumeration colour, effect_enumeration effect) {
char format [8] = "\033[ ;3 m";
format [2] = (char) (effect % effect_count) + '0';
format [5] = (char) (colour % colour_count) + '0';
echo (format);
}
static void terminal_cancel (void) {
echo ("\033[0m");
}
static void terminal_show_cursor (bool show) {
if (show) {
echo ("\033[?25h");
} else {
echo ("\033[?25l");
}
}
static int file_open (const char * path, int mode) {
int descriptor = -1;
fatal_failure (path == null, "file_open: File path is null pointer.");
fatal_failure ((descriptor = open (path, mode)) == -1, "file_open: Function 'open' returned invalid descriptor.");
return (descriptor);
}
static int file_close (int file) {
fatal_failure (file == -1, "file_close: Invalid file descriptor.");
fatal_failure (close (file) == -1, "file_close: Function 'close' returned invalid code.");
return (-1);
}
static void file_read (int file, void * data, ulong 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.");
fatal_failure (read (file, data, size) == ~0l, "file_write: Function 'read' returned invalid code.");
}
static void file_write (int file, const void * data, ulong 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.");
fatal_failure (write (file, data, size) == ~0l, "file_write: Function 'write' returned invalid code.");
}
static void file_echo (int file, const char * data) {
file_write (file, data, string_length (data));
}
static ulong file_seek (int file, int whence) {
ulong offset = ~0ul;
fatal_failure (file == -1, "file_seek: Invalid file descriptor.");
fatal_failure ((offset = (ulong) lseek (file, 0, whence)) == ~0ul, "file_seek: Function 'lseek' returned invalid code.");
return (offset);
}
static ulong file_size (const char * path) {
struct stat data = { 0 };
fatal_failure (lstat (path, & data) == -1, "file_size: Function 'lstat' returned invalid code.");
return ((ulong) data.st_size);
}
static int file_type (const char * name) {
const char * extensions [file_type_count] = {
".c", ".h", ".adb", ".ads", ".cpp", ".hpp", ".f90", ".pas",
".asm", ".eax", ".gas", ".fasm", ".txt", ".md", ".html", ".glsl",
".sh", ".py", ".tcl", ".4th", ".x", ".xhla", ".xs", ".xd",
".xiri", ".xofya", ".xienna", ".xenka", ".xiyagi", ".xoule", ".xikoku", ".xdo"
};
int type = 0;
for (; * name != '.'; ++name);
for (type = 0; type != file_type_count; ++type) {
if (string_compare (name, extensions [type])) {
return (type);
}
}
return (file_type_error);
}
static void * file_record (const char * path) {
int file = -1;
ulong size = 0;
char * 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 char * file_import (const char * path) {
int file = -1;
ulong size = 0;
char * 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 void file_export (const char * path, const void * data, ulong size) {
int file = -1;
fatal_failure (path == null, "file_export: File path is null pointer.");
fatal_failure (data == null, "file_export: Data is null pointer.");
fatal_failure (size == 0, "file_export: Size is zero.");
file = file_open (path, file_flag_write | file_flag_create | file_flag_truncate);
file_write (file, data, size);
file = file_close (file);
}
static char * number_to_string (int number) {
static char string [33];
int i, sign;
string_nullify (string, sizeof (string));
if (number == 0) {
string [0] = '0';
string [1] = '\0';
return (string);
}
if (number < 0) {
number *= -1;
sign = 1;
} else {
sign = 0;
}
for (i = (string [0] == '-'); number != 0; ++i) {
string [i] = (char) (number % 10) + '0';
number /= 10;
}
if (sign != 0) {
string [i] = '-';
++i;
}
string [i] = '\0';
string_reverse (string);
return (string);
}
static char * format_to_string (int number, int sign, int base, ulong amount, char character) {
static char string [33];
int i;
string_nullify (string, sizeof (string));
if (number == 0) {
string [0] = '0';
string [1] = '\0';
string_realign (string, amount, character);
return (string);
}
if (number < 0) {
number *= -1;
}
for (i = (string [0] == '-'); number != 0; ++i) {
string [i] = "0123456789ABCDEF" [number % base];
number /= base;
}
if (sign != 0) {
string [i] = '-';
++i;
}
string [i] = '\0';
string_reverse (string);
string_realign (string, amount, character);
return (string);
}
static char * format (const char * base, ...) {
static char 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, int))); break;
case 's': string_concatenate (string, va_arg (list, char *)); break;
default: string_concatenate (string, "?"); break;
}
} break;
default: {
string_concatenate_limit (string, base, 1);
} break;
}
}
va_end (list);
return (string);
}
static void print (const char * 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': {
char * string = number_to_string (va_arg (list, int));
output (string, string_length (string));
} break;
case 't': {
int toggle = (va_arg (list, int));
terminal_colour ((toggle == true) ? colour_green : colour_red, effect_normal);
output ((toggle == true) ? "+" : "-", 1);
terminal_cancel ();
} break;
case 'b': {
int boolean = (va_arg (list, int));
output ((boolean == true) ? "true" : "false", (boolean == true) ? 4 : 5);
} break;
case 'c': {
char character = (char) va_arg (list, int);
output (& character, 1);
} break;
case 's': {
char * string = va_arg (list, char *);
output (string, string_length (string));
} break;
default: {
output ("?", 1);
} break;
}
} break;
case '/': {
++format;
switch (* format) {
case '/': output ("/", 1); break;
case '0': terminal_colour (colour_grey, effect_normal); break;
case '1': terminal_colour (colour_red, effect_normal); break;
case '2': terminal_colour (colour_green, effect_normal); break;
case '3': terminal_colour (colour_yellow, effect_normal); break;
case '4': terminal_colour (colour_blue, effect_normal); break;
case '5': terminal_colour (colour_pink, effect_normal); break;
case '6': terminal_colour (colour_cyan, effect_normal); break;
case '7': terminal_colour (colour_white, effect_normal); break;
case '-': terminal_cancel (); break;
default: output ("?", 1); break;
}
} break;
default: {
output (format, 1);
} break;
}
}
va_end (list);
}
#ifdef use_mathematics
#include <math.h>
#define pi (3.14159265f)
static float sign (float x) { return ((x > 0.0f) ? +1.0f : -1.0f); }
static float square_root (float x) { return (sqrtf (x)); }
static float cube_root (float x) { return (cbrtf (x)); }
static float sine (float x) { return (sinf (x)); }
static float cosine (float x) { return (cosf (x)); }
static float tangent (float x) { return (tanf (x)); }
static float arc_sine (float x) { return (asinf (x)); }
static float arc_cosine (float x) { return (acosf (x)); }
static float arc_tangent (float x) { return (atanf (x)); }
static float cosecant (float x) { return (1.0f / sinf (x)); }
static float secant (float x) { return (1.0f / cosf (x)); }
static float cotangent (float x) { return (1.0f / tanf (x)); }
#endif
#ifdef use_png_library
#include <stdio.h>
#include <png.h>
static void * import_png_image (const char * path, uint * width, uint * height) {
FILE * file;
uint * data;
uint index;
png_byte colour_type = 0;
png_byte bit_depth = 0;
png_bytep * row_pointers = null;
png_structp structure = null;
png_infop information = null;
file = fopen (path, "rb");
fatal_failure (file == null, path);
structure = png_create_read_struct (PNG_LIBPNG_VER_STRING, null, null, null);
information = png_create_info_struct (structure);
png_init_io (structure, file);
png_read_info (structure, information);
* width = png_get_image_width (structure, information);
* height = png_get_image_height (structure, information);
colour_type = png_get_color_type (structure, information);
bit_depth = png_get_bit_depth (structure, information);
if (bit_depth == 16) {
png_set_strip_16 (structure);
}
if (colour_type == PNG_COLOR_TYPE_PALETTE) {
png_set_palette_to_rgb (structure);
}
if ((colour_type == PNG_COLOR_TYPE_GRAY) && (bit_depth < 8)) {
png_set_expand_gray_1_2_4_to_8 (structure);
}
if (png_get_valid (structure, information, PNG_INFO_tRNS)) {
png_set_tRNS_to_alpha (structure);
}
if ((colour_type == PNG_COLOR_TYPE_RGB) || (colour_type == PNG_COLOR_TYPE_GRAY) || (colour_type == PNG_COLOR_TYPE_PALETTE)) {
png_set_filler (structure, 0xff, PNG_FILLER_AFTER);
}
if ((colour_type == PNG_COLOR_TYPE_GRAY) || (colour_type == PNG_COLOR_TYPE_GRAY_ALPHA)) {
png_set_gray_to_rgb (structure);
}
png_read_update_info (structure, information);
row_pointers = allocate ((* height) * sizeof (* row_pointers));
for (index = 0; index < (* height); ++index) {
row_pointers [index] = allocate (png_get_rowbytes (structure, information));
}
png_read_image (structure, row_pointers);
fclose (file);
data = allocate ((* width) * (* height) * sizeof (* data));
for (index = 0; index < (* height); ++index) {
memory_copy (& data [index * (* width)], row_pointers [index], (* width) * sizeof (* data));
row_pointers [index] = deallocate (row_pointers [index]);
}
row_pointers = deallocate (row_pointers);
png_destroy_read_struct (& structure, & information, null);
return (data);
}
static void export_png_image (const char * path, uint * data, uint width, uint height) {
png_image image = { 0 };
image.version = PNG_IMAGE_VERSION;
image.format = PNG_FORMAT_RGBA;
image.width = width;
image.height = height;
png_image_write_to_file (& image, path, 0, data, 0, null);
png_image_free (& image);
}
#endif