271 lines
7.8 KiB
C
271 lines
7.8 KiB
C
|
#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);
|
||
|
}
|