xarbon/xarbon.c

271 lines
7.8 KiB
C
Raw Normal View History

2024-09-28 13:33:22 -04:00
#include <xolatile/xyntax.h>
#include <png.h>
#include "language/ada.h"
#include "language/assembly.h"
#include "language/c.h"
#include "language/c++.h"
#include "language/eaxhla.h"
#include "language/flat.h"
#include "language/fortran.h"
#include "language/xofya.h"
static struct {
void (* highlighter) (void);
char * option_short;
char * option_long;
} const language [] = {
{ highlight_ada, "-A", "--ada" },
{ highlight_assembly, "-S", "--assembly" },
{ highlight_c, "-C", "--c" },
{ highlight_cpp, "-P", "--c++" },
{ highlight_eaxhla, "-E", "--eaxhla" },
{ highlight_flat, "-T", "--flat" },
{ highlight_fortran, "-F", "--fortran" },
{ highlight_xofya, "-X", "--xofya" }
};
static int background = 0xff181818;
static int tab_width = 8;
static int render_border = 10;
static int * render_image = null;
static int render_width = 0;
static int render_height = 0;
static int * font_source = null;
static int font_width = 0;
static int font_height = 0;
static int line_number = 0;
static int line_digits = 0;
static void import_png_as_glyphmap (const char * path) {
png_image image = { 0 };
image.version = PNG_IMAGE_VERSION;
png_image_begin_read_from_file (& image, path);
image.format = PNG_FORMAT_RGBA;
font_width = image.width / 16;
font_height = image.height / 6;
font_source = allocate (image.width * image.height * (int) sizeof (* font_source));
png_image_finish_read (& image, null, font_source, 0, null);
png_image_free (& image);
}
static void export_render_as_png (const char * path) {
png_image image = { 0 };
image.version = PNG_IMAGE_VERSION;
image.format = PNG_FORMAT_RGBA;
image.width = (unsigned int) render_width;
image.height = (unsigned int) render_height;
png_image_write_to_file (& image, path, 0, render_image, 0, null);
png_image_free (& image);
}
static int fetch_width (const char * data) {
int image_width = 0;
int count = 0;
do {
if (* data == '\t') {
count += tab_width;
} else if (* data == '\n') {
image_width = (++count > image_width) ? count : image_width;
count = 0;
} else {
++count;
}
} while (* (++data) != '\0');
return (image_width - 1);
}
static int fetch_height (const char * data) {
int image_height = 0;
int count = 0;
do {
if (* data == '\n') {
++image_height;
}
} while (* (++data) != '\0');
count = image_height + 1;
do {
++line_digits;
count /= 10;
} while (count > 0);
return (image_height + 1);
}
static int interpolate_pixel (int pixel, int colour) {
int r, g, b, a;
a = (pixel >> 24) & 0xff;
if (a == 0x00) {
return (background);
} else if (a == 0xff) {
return (colour);
} else {
r = (((background >> 0) & 0xff) * (0xff - a) + ((colour >> 0) & 0xff) * a) / 0xff;
g = (((background >> 8) & 0xff) * (0xff - a) + ((colour >> 8) & 0xff) * a) / 0xff;
b = (((background >> 16) & 0xff) * (0xff - a) + ((colour >> 16) & 0xff) * a) / 0xff;
return ((r << 0) | (g << 8) | (b << 16) | 0xff000000);
}
}
static void render_character (char character, int * x, int * y, int colour) {
int offset_x = 0;
int offset_y = 0;
int offset_u = (character - ' ') % 16;
int offset_v = (character - ' ') / 16;
for (offset_y = 0; offset_y < font_height; ++offset_y) {
for (offset_x = 0; offset_x < font_width; ++offset_x) {
int destination = (* y + offset_y) * render_width + (* x + offset_x);
int source = (offset_v * font_height + offset_y) * font_width * 16 + (offset_u * font_width + offset_x);
render_image [destination] = interpolate_pixel (font_source [source], colour);
}
}
* x += font_width;
}
static void render_string (char * string, int length, int * x, int * y, int colour) {
int offset;
for (offset = 0; offset < length; ++offset) {
if (string [offset] == '\t') {
* x += font_width * tab_width;
} else if (string [offset] == '\n') {
* y += font_height;
* x = render_border;
render_string (format_to_string (++line_number, false, 10, line_digits, ' '), line_digits, x, y, (int) 0xffeeeeee);
* x += font_width;
} else {
render_character (string [offset], x, y, colour);
}
}
}
int main (int argc, char * * argv) {
int offset = 0;
int select = 0;
int length = 0;
int x = render_border;
int y = render_border;
char * buffer = null;
if (argc != 1) {
if (string_compare (argv [1], "-v") || string_compare (argv [1], "--version")) {
echo ("xarbon: Source code renderer (version 144)\n");
exit (log_success);
} else if (string_compare (argv [1], "-l") || string_compare (argv [1], "--license")) {
echo ("xarbon: Source code renderer (GNU/GPLv3)\n");
exit (log_success);
} else if (string_compare (argv [1], "-a") || string_compare (argv [1], "--author")) {
echo ("xarbon: Source code renderer (Ognjen 'xolatile' Milan Robovic)\n");
exit (log_success);
} else if (string_compare (argv [1], "-h") || string_compare (argv [1], "--help")) {
echo ("xarbon: Source code renderer:\n");
echo ("Example usage:\n");
echo ("\t$ cat file.ext | xarbon [flag] -- You need to pass language flag in this case.\n");
echo ("\t$ xarbon [flag] < file.ext -- You need to pass language flag in this case.\n");
echo ("\t$ xarbon file.ext -- Language is automatically detected in this case.\n");
echo ("Supported languages:\n");
echo ("\t -C --c -- C syntax\n");
echo ("\t -A --ada -- Ada syntax\n");
echo ("\t -P --cpp -- C++ syntax \n");
echo ("\t -S --assembly -- General assembly syntax\n");
echo ("\t -T --flat -- Flat assembly syntax\n");
echo ("\t -F --fortran -- Fortran syntax\n");
echo ("\t -X --xofya -- Xofya syntax\n");
exit (log_success);
} else {
int index;
for (index = 0; index < (int) (sizeof (language) / sizeof (* language)); ++index) {
if ((string_compare (argv [1], language [index].option_short) == true)
|| (string_compare (argv [1], language [index].option_long) == true)) {
language [index].highlighter ();
break;
}
}
if (syntax_active == false) {
select = file_type (argv [1]);
buffer = file_import (argv [1]);
}
}
}
if (buffer == null) {
buffer = record ();
}
if (syntax_active == false) {
if ((select == file_type_c_source) || (select == file_type_c_header)) {
highlight_c ();
} else if ((select == file_type_ada_body) || (select == file_type_ada_specification)) {
highlight_ada ();
} else if ((select == file_type_cpp_source) || (select == file_type_cpp_header)) {
highlight_cpp ();
} else if (select == file_type_common_assembly) {
highlight_assembly ();
} else if (select == file_type_flat_assembly) {
highlight_flat ();
} else if (select == file_type_fortran_90) {
highlight_fortran ();
/*} else if (select == file_type_xofya) {
highlight_xofya ();*/
}
}
import_png_as_glyphmap ("/usr/local/bin/xarbon_font.png");
render_width = fetch_width (buffer) * font_width + 2 * render_border;
render_height = fetch_height (buffer) * font_height + 2 * render_border;
render_width += (line_digits + 1) * font_width;
render_image = allocate (render_width * render_height * (int) sizeof (* render_image));
for (offset = 0; offset < render_width * render_height; ++offset) {
render_image [offset] = background;
}
render_string (format_to_string (++line_number, false, 10, line_digits, ' '), line_digits, & x, & y, (int) 0xffeeeeee);
x += font_width;
for (offset = 0; buffer [offset] != '\0'; offset += length) {
select = syntax_select (& buffer [offset], & length);
render_string (& buffer [offset], length, & x, & y, (select >= syntax_count) ? (int) background : syntax_colour [select]);
}
export_render_as_png ("./xarbon.png");
render_image = deallocate (render_image);
font_source = deallocate (font_source);
buffer = deallocate (buffer);
return (log_success);
}