Fast and reasonably complete (framebuffer) terminal emulator (Zig fork)

Compare changes

Choose any two refs to compare.

+3
.gitignore
···
+
*.d
+
*.o
+
.zig-cache
+18 -5
LICENSE
···
-
Copyright (C) 2022-2023 mintsuki and contributors.
+
Copyright (C) 2022-2025 mintsuki and contributors.
-
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
Redistribution and use in source and binary forms, with or without
+
modification, are permitted provided that the following conditions are met:
-
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
1. Redistributions of source code must retain the above copyright notice, this
+
list of conditions and the following disclaimer.
-
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
2. Redistributions in binary form must reproduce the above copyright notice,
+
this list of conditions and the following disclaimer in the documentation
+
and/or other materials provided with the distribution.
-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+23 -9
README.md
···
### Quick usage
To quickly set up and use a framebuffer Flanterm instance, it is possible to
-
use the `flanterm_fb_simple_init()` function as such:
+
use the `flanterm_fb_init()` function as such:
```c
-
#include <flanterm/flanterm.h>
-
#include <flanterm/backends/fb.h>
+
#include <flanterm.h>
+
#include <flanterm_backends/fb.h>
-
struct flanterm_context *ft_ctx = flanterm_fb_simple_init(
-
framebuffer_ptr, framebuffer_width, framebuffer_height, framebuffer_pitch
-
);
+
struct flanterm_context *ft_ctx = flanterm_fb_init(
+
NULL,
+
NULL,
+
framebuffer_ptr, width, height, pitch,
+
red_mask_size, red_mask_shift,
+
green_mask_size, green_mask_shift,
+
blue_mask_size, blue_mask_shift,
+
NULL,
+
NULL, NULL,
+
NULL, NULL,
+
NULL, NULL,
+
NULL, 0, 0, 1,
+
0, 0,
+
0
+
);
```
-
Where `framebuffer_{ptr,width,height,pitch}` represent the corresponding info
-
about the framebuffer to use for this given instance.
+
Where `framebuffer_ptr, width, height, pitch` and `{red,green,blue}_mask_{size,shift}`
+
represent the corresponding info about the framebuffer to use for this given instance.
+
+
The meaning of the other arguments can be found in `flanterm_backends/fb.h`.
To then print to the terminal instance, simply use the `flanterm_write()`
function on the given instance. For example:
```c
-
#include <flanterm/flanterm.h>
+
#include <flanterm.h>
const char msg[] = "Hello world\n";
+17
README.zig.md
···
+
# Flanterm
+
Adapted from [https://codeberg.org/Mintsuki/Flanterm](https://codeberg.org/Mintsuki/Flanterm)
+
for Zig. Read the C code and original README for more information.
+
+
## Usage
+
First, add the package to your build.zig.zon:
+
`zig fetch --save git+https://tangled.sh/@sydney.blue/flanterm.zig#trunk`
+
Then, add the following to your build.zig:
+
```zig
+
const flanterm_dep = b.dependency("flanterm", .{});
+
const flanterm_mod = flanterm.module("flanterm");
+
exe.root_module.addImport("flanterm", flanterm_mod);
+
```
+
+
Now, you can import the `flanterm` module and use the helpers. More
+
bindings will be added as needed, feel free to contribute anything
+
you would find useful.
-1160
backends/fb.c
···
-
/* Copyright (C) 2022-2023 mintsuki and contributors.
-
*
-
* Redistribution and use in source and binary forms, with or without
-
* modification, are permitted provided that the following conditions are met:
-
*
-
* 1. Redistributions of source code must retain the above copyright notice,
-
* this list of conditions and the following disclaimer.
-
*
-
* 2. Redistributions in binary form must reproduce the above copyright notice,
-
* this list of conditions and the following disclaimer in the documentation
-
* and/or other materials provided with the distribution.
-
*
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
-
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-
* POSSIBILITY OF SUCH DAMAGE.
-
*/
-
-
#include <stdint.h>
-
#include <stddef.h>
-
-
#include "../flanterm.h"
-
#include "fb.h"
-
-
void *memset(void *, int, size_t);
-
void *memcpy(void *, const void *, size_t);
-
-
#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
-
-
#ifndef FLANTERM_FB_BUMP_ALLOC_POOL_SIZE
-
#define FLANTERM_FB_BUMP_ALLOC_POOL_SIZE (64*1024*1024)
-
#endif
-
-
static uint8_t bump_alloc_pool[FLANTERM_FB_BUMP_ALLOC_POOL_SIZE];
-
static size_t bump_alloc_ptr = 0;
-
-
static void *bump_alloc(size_t s) {
-
size_t next_ptr = bump_alloc_ptr + s;
-
if (next_ptr > FLANTERM_FB_BUMP_ALLOC_POOL_SIZE) {
-
return NULL;
-
}
-
void *ret = &bump_alloc_pool[bump_alloc_ptr];
-
bump_alloc_ptr = next_ptr;
-
return ret;
-
}
-
-
#endif
-
-
// Builtin font originally taken from:
-
// https://github.com/viler-int10h/vga-text-mode-fonts/raw/master/FONTS/PC-OTHER/TOSH-SAT.F16
-
static const uint8_t builtin_font[] = {
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x81, 0x81, 0xa5, 0xa5, 0x81,
-
0x81, 0xa5, 0x99, 0x81, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x7e, 0xff,
-
0xff, 0xdb, 0xdb, 0xff, 0xff, 0xdb, 0xe7, 0xff, 0x7e, 0x3c, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10,
-
0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe,
-
0x7c, 0x7c, 0x38, 0x38, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
-
0x3c, 0x3c, 0xdb, 0xff, 0xff, 0xdb, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0xff, 0x66, 0x18, 0x18,
-
0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78,
-
0x78, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
-
0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xcc, 0x84, 0x84, 0xcc, 0x78, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd,
-
0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x1e,
-
0x0e, 0x1e, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0xfc, 0x30, 0x30,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x18, 0x1c, 0x1e, 0x16, 0x12,
-
0x10, 0x10, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x38, 0x2c,
-
0x26, 0x32, 0x3a, 0x2e, 0x26, 0x22, 0x62, 0xe2, 0xc6, 0x0e, 0x0c, 0x00,
-
0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf8, 0xfe,
-
0xf8, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
-
0x06, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x30, 0x78, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x78,
-
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
-
0xcc, 0xcc, 0x00, 0xcc, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb,
-
0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c,
-
0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78,
-
0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x78, 0x30, 0xfc, 0x00, 0x00,
-
0x00, 0x00, 0x30, 0x78, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
-
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
-
0x30, 0x30, 0xfc, 0x78, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x18, 0x0c, 0xfe, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0xfe, 0x60, 0x30, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-
0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x24, 0x66, 0xff, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c,
-
0x38, 0x38, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x30, 0x78, 0x78, 0x78, 0x78, 0x30, 0x30, 0x30, 0x00, 0x30,
-
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c,
-
0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
-
0x00, 0x18, 0x18, 0x7c, 0xc6, 0xc0, 0xc0, 0x7c, 0x06, 0x06, 0xc6, 0x7c,
-
0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x0c, 0x0c, 0x18, 0x38,
-
0x30, 0x60, 0x60, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
-
0x6c, 0x38, 0x30, 0x76, 0xde, 0xcc, 0xcc, 0xde, 0x76, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x60, 0x60, 0x60,
-
0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30,
-
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x38, 0xfe, 0x38, 0x6c, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
-
0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06,
-
0x0c, 0x0c, 0x18, 0x38, 0x30, 0x60, 0x60, 0xc0, 0xc0, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xc6, 0xc6, 0xc6,
-
0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
-
0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
-
0x06, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0x06, 0xc6,
-
0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc,
-
0xfe, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
-
0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x3c, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-
0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18,
-
0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
-
0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c,
-
0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
-
0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00,
-
0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c,
-
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00,
-
0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x60,
-
0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x00, 0x30,
-
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde,
-
0xde, 0xde, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
-
0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xc6, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-
0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0,
-
0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xcc,
-
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xcc, 0xf8, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
-
0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0,
-
0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
-
0xc0, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6,
-
0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30,
-
0x30, 0x30, 0x30, 0x30, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c,
-
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0xc6, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6,
-
0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
-
0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6,
-
0xee, 0xfe, 0xd6, 0xd6, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0xc6, 0xc6, 0xe6, 0xe6, 0xf6, 0xde, 0xce, 0xce, 0xc6, 0xc6,
-
0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-
0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc6,
-
0xc6, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xf6, 0xda,
-
0x6c, 0x06, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc,
-
0xd8, 0xcc, 0xcc, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
-
0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-
0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6,
-
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xd6, 0xfe, 0x6c,
-
0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x38,
-
0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc,
-
0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0xfe, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc0, 0xc0,
-
0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60,
-
0x60, 0x60, 0x60, 0x60, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
-
0x60, 0x60, 0x30, 0x38, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-
0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
-
0x00, 0x00, 0x18, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x06, 0x06,
-
0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
-
0xc0, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xe6, 0xdc, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc6,
-
0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x76, 0xce, 0xc6,
-
0xc6, 0xc6, 0xc6, 0xce, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30,
-
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xce, 0xc6,
-
0xc6, 0xc6, 0xce, 0x76, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0xc0, 0xc0,
-
0xc0, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x18, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-
0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x1e, 0x06, 0x06,
-
0x06, 0x06, 0x06, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0xc0, 0xc0,
-
0xc0, 0xc6, 0xcc, 0xd8, 0xf0, 0xf0, 0xd8, 0xcc, 0xc6, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-
0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6,
-
0xd6, 0xd6, 0xd6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-
0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0xe6, 0xc6,
-
0xc6, 0xc6, 0xe6, 0xdc, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x76, 0xce, 0xc6, 0xc6, 0xc6, 0xce, 0x76, 0x06, 0x06, 0x06, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0xe6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
-
0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0,
-
0x70, 0x1c, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30,
-
0x30, 0xfe, 0x30, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-
0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
-
0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6,
-
0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
-
0xc6, 0xc6, 0xce, 0x76, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0xfe, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xfe, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x1c, 0x30, 0x30, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x30, 0x30,
-
0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00,
-
0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x30,
-
0x30, 0x30, 0x30, 0x1c, 0x30, 0x30, 0x30, 0x30, 0xe0, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x38, 0x38, 0x6c,
-
0x6c, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
-
0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x18, 0xcc, 0x78, 0x00,
-
0x00, 0x00, 0x6c, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-
0x7c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xc6,
-
0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
-
0x00, 0x7c, 0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x6c, 0x6c, 0x00, 0x7c, 0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xc6,
-
0x7e, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0x06, 0x06,
-
0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38,
-
0x00, 0x7c, 0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc6,
-
0x7c, 0x18, 0x0c, 0x38, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6,
-
0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c,
-
0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00,
-
0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc0, 0xc0, 0xc0,
-
0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x00, 0x38, 0x18, 0x18,
-
0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
-
0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
-
0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-
0x3c, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6,
-
0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00,
-
0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
-
0x18, 0x30, 0x60, 0x00, 0xfe, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0,
-
0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x36, 0x36,
-
0x76, 0xde, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3c,
-
0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00,
-
0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-
0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6,
-
0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
-
0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
-
0x00, 0x10, 0x38, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-
0x7c, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xc6, 0xc6, 0xc6,
-
0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c,
-
0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0x76, 0x06, 0xc6, 0x7c, 0x00,
-
0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-
0x7c, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-
0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
-
0x30, 0x78, 0xcc, 0xc0, 0xc0, 0xcc, 0x78, 0x30, 0x30, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x38, 0x6c, 0x60, 0x60, 0x60, 0xf8, 0x60, 0x60, 0x60, 0xe6,
-
0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0xfc,
-
0x30, 0xfc, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xcc,
-
0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xcc, 0xc6, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18,
-
0x18, 0xd8, 0x70, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0x06, 0x06,
-
0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30,
-
0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
-
0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-
0x7c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0xc6, 0xc6, 0xc6,
-
0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
-
0x00, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
-
0x76, 0xdc, 0x00, 0xc6, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6,
-
0xc6, 0x00, 0x00, 0x00, 0x00, 0x78, 0xd8, 0xd8, 0x6c, 0x00, 0xfc, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
-
0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xc6,
-
0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0xfe, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0xc0, 0xc2, 0xc6, 0xcc, 0xd8, 0x30, 0x60, 0xdc, 0x86, 0x0c,
-
0x18, 0x3e, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc2, 0xc6, 0xcc, 0xd8, 0x30,
-
0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30,
-
0x00, 0x30, 0x30, 0x30, 0x78, 0x78, 0x78, 0x78, 0x30, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36,
-
0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x88, 0x22, 0x88,
-
0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
-
0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
-
0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
-
0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18,
-
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18,
-
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18,
-
0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
-
0x36, 0x36, 0x36, 0xf6, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x36, 0x36, 0x36,
-
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xf8, 0x18,
-
0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
-
0x36, 0xf6, 0xf6, 0x06, 0x06, 0xf6, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36,
-
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x06,
-
0x06, 0xf6, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-
0x36, 0xf6, 0xf6, 0x06, 0x06, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0xfe, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18,
-
0x18, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x1f, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff,
-
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x1f, 0x18, 0x18, 0x18,
-
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
-
0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-
0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x1f, 0x18, 0x18, 0x1f, 0x1f, 0x18,
-
0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
-
0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-
0x36, 0x37, 0x37, 0x30, 0x30, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x30, 0x30, 0x37, 0x37, 0x36,
-
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0xf7, 0x00,
-
0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0xff, 0xff, 0x00, 0x00, 0xf7, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36,
-
0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, 0x30, 0x30, 0x37, 0x37, 0x36,
-
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
-
0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
-
0x36, 0xf7, 0xf7, 0x00, 0x00, 0xf7, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36,
-
0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff,
-
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x36, 0x36, 0x36,
-
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f,
-
0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
-
0x18, 0x1f, 0x1f, 0x18, 0x18, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x18, 0x18, 0x1f, 0x1f, 0x18,
-
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
-
0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-
0x36, 0x36, 0x36, 0xff, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-
0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0xff, 0xff, 0x18,
-
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8,
-
0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x1f, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0,
-
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
-
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
-
0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x76, 0xd6, 0xdc, 0xc8, 0xc8, 0xdc, 0xd6, 0x76, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
-
0xd8, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0,
-
0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x7e, 0xfe, 0x24, 0x24, 0x24, 0x24, 0x66, 0xc6, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0xfe, 0xfe, 0xc2, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc2, 0xfe,
-
0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xc8, 0xcc,
-
0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x6c, 0x60, 0xc0, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0xfc, 0x98, 0x18, 0x18, 0x18, 0x18,
-
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x30, 0x30, 0x78, 0xcc, 0xcc,
-
0xcc, 0x78, 0x30, 0x30, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
-
0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c,
-
0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xcc, 0x60, 0x30, 0x78, 0xcc,
-
0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x76, 0xbb, 0x99, 0x99, 0xdd, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x02, 0x06, 0x3c, 0x6c, 0xce, 0xd6, 0xd6, 0xe6, 0x6c, 0x78,
-
0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x60, 0xc0, 0xc0, 0xfe,
-
0xc0, 0xc0, 0x60, 0x30, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
-
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0xfc,
-
0x30, 0x30, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
-
0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, 0x36, 0x30, 0x30, 0x30,
-
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x18, 0x18, 0x18,
-
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
-
0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xcc,
-
0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c,
-
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c, 0x00, 0x00,
-
0x00, 0xd8, 0xec, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x0c, 0x18, 0x30, 0x60, 0x7c,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
0x00, 0x00, 0x00, 0x00
-
};
-
-
#ifdef FLANTERM_FB_SUPPORT_BPP
-
static inline __attribute__((always_inline)) uint32_t convert_colour(struct flanterm_context *_ctx, uint32_t colour) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
uint32_t r = (colour >> 16) & 0xff;
-
uint32_t g = (colour >> 8) & 0xff;
-
uint32_t b = colour & 0xff;
-
return (r << ctx->red_mask_shift) | (g << ctx->green_mask_shift) | (b << ctx->blue_mask_shift);
-
}
-
#else
-
#define convert_colour(CTX, COLOUR) (COLOUR)
-
#endif
-
-
static void flanterm_fb_save_state(struct flanterm_context *_ctx) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
ctx->saved_state_text_fg = ctx->text_fg;
-
ctx->saved_state_text_bg = ctx->text_bg;
-
ctx->saved_state_cursor_x = ctx->cursor_x;
-
ctx->saved_state_cursor_y = ctx->cursor_y;
-
}
-
-
static void flanterm_fb_restore_state(struct flanterm_context *_ctx) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
ctx->text_fg = ctx->saved_state_text_fg;
-
ctx->text_bg = ctx->saved_state_text_bg;
-
ctx->cursor_x = ctx->saved_state_cursor_x;
-
ctx->cursor_y = ctx->saved_state_cursor_y;
-
}
-
-
static void flanterm_fb_swap_palette(struct flanterm_context *_ctx) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
uint32_t tmp = ctx->text_bg;
-
ctx->text_bg = ctx->text_fg;
-
ctx->text_fg = tmp;
-
}
-
-
static void plot_char(struct flanterm_context *_ctx, struct flanterm_fb_char *c, size_t x, size_t y) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
if (x >= _ctx->cols || y >= _ctx->rows) {
-
return;
-
}
-
-
#ifdef FLANTERM_FB_DISABLE_CANVAS
-
uint32_t default_bg = ctx->default_bg;
-
#endif
-
-
x = ctx->offset_x + x * ctx->glyph_width;
-
y = ctx->offset_y + y * ctx->glyph_height;
-
-
bool *glyph = &ctx->font_bool[c->c * ctx->font_height * ctx->font_width];
-
// naming: fx,fy for font coordinates, gx,gy for glyph coordinates
-
for (size_t gy = 0; gy < ctx->glyph_height; gy++) {
-
uint8_t fy = gy / ctx->font_scale_y;
-
volatile uint32_t *fb_line = ctx->framebuffer + x + (y + gy) * (ctx->pitch / 4);
-
-
#ifndef FLANTERM_FB_DISABLE_CANVAS
-
uint32_t *canvas_line = ctx->canvas + x + (y + gy) * ctx->width;
-
#endif
-
-
for (size_t fx = 0; fx < ctx->font_width; fx++) {
-
bool draw = glyph[fy * ctx->font_width + fx];
-
for (size_t i = 0; i < ctx->font_scale_x; i++) {
-
size_t gx = ctx->font_scale_x * fx + i;
-
#ifndef FLANTERM_FB_DISABLE_CANVAS
-
uint32_t bg = c->bg == 0xffffffff ? canvas_line[gx] : c->bg;
-
uint32_t fg = c->fg == 0xffffffff ? canvas_line[gx] : c->fg;
-
#else
-
uint32_t bg = c->bg == 0xffffffff ? default_bg : c->bg;
-
uint32_t fg = c->fg == 0xffffffff ? default_bg : c->fg;
-
#endif
-
fb_line[gx] = draw ? fg : bg;
-
}
-
}
-
}
-
}
-
-
static void plot_char_fast(struct flanterm_context *_ctx, struct flanterm_fb_char *old, struct flanterm_fb_char *c, size_t x, size_t y) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
if (x >= _ctx->cols || y >= _ctx->rows) {
-
return;
-
}
-
-
x = ctx->offset_x + x * ctx->glyph_width;
-
y = ctx->offset_y + y * ctx->glyph_height;
-
-
#ifdef FLANTERM_FB_DISABLE_CANVAS
-
uint32_t default_bg = ctx->default_bg;
-
#endif
-
-
bool *new_glyph = &ctx->font_bool[c->c * ctx->font_height * ctx->font_width];
-
bool *old_glyph = &ctx->font_bool[old->c * ctx->font_height * ctx->font_width];
-
for (size_t gy = 0; gy < ctx->glyph_height; gy++) {
-
uint8_t fy = gy / ctx->font_scale_y;
-
volatile uint32_t *fb_line = ctx->framebuffer + x + (y + gy) * (ctx->pitch / 4);
-
#ifndef FLANTERM_FB_DISABLE_CANVAS
-
uint32_t *canvas_line = ctx->canvas + x + (y + gy) * ctx->width;
-
#endif
-
for (size_t fx = 0; fx < ctx->font_width; fx++) {
-
bool old_draw = old_glyph[fy * ctx->font_width + fx];
-
bool new_draw = new_glyph[fy * ctx->font_width + fx];
-
if (old_draw == new_draw)
-
continue;
-
for (size_t i = 0; i < ctx->font_scale_x; i++) {
-
size_t gx = ctx->font_scale_x * fx + i;
-
#ifndef FLANTERM_FB_DISABLE_CANVAS
-
uint32_t bg = c->bg == 0xffffffff ? canvas_line[gx] : c->bg;
-
uint32_t fg = c->fg == 0xffffffff ? canvas_line[gx] : c->fg;
-
#else
-
uint32_t bg = c->bg == 0xffffffff ? default_bg : c->bg;
-
uint32_t fg = c->fg == 0xffffffff ? default_bg : c->fg;
-
#endif
-
fb_line[gx] = new_draw ? fg : bg;
-
}
-
}
-
}
-
}
-
-
static inline bool compare_char(struct flanterm_fb_char *a, struct flanterm_fb_char *b) {
-
return !(a->c != b->c || a->bg != b->bg || a->fg != b->fg);
-
}
-
-
static void push_to_queue(struct flanterm_context *_ctx, struct flanterm_fb_char *c, size_t x, size_t y) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
if (x >= _ctx->cols || y >= _ctx->rows) {
-
return;
-
}
-
-
size_t i = y * _ctx->cols + x;
-
-
struct flanterm_fb_queue_item *q = ctx->map[i];
-
-
if (q == NULL) {
-
if (compare_char(&ctx->grid[i], c)) {
-
return;
-
}
-
q = &ctx->queue[ctx->queue_i++];
-
q->x = x;
-
q->y = y;
-
ctx->map[i] = q;
-
}
-
-
q->c = *c;
-
}
-
-
static void flanterm_fb_revscroll(struct flanterm_context *_ctx) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
for (size_t i = (_ctx->scroll_bottom_margin - 1) * _ctx->cols - 1;
-
i >= _ctx->scroll_top_margin * _ctx->cols; i--) {
-
if (i == (size_t)-1) {
-
break;
-
}
-
struct flanterm_fb_char *c;
-
struct flanterm_fb_queue_item *q = ctx->map[i];
-
if (q != NULL) {
-
c = &q->c;
-
} else {
-
c = &ctx->grid[i];
-
}
-
push_to_queue(_ctx, c, (i + _ctx->cols) % _ctx->cols, (i + _ctx->cols) / _ctx->cols);
-
}
-
-
// Clear the first line of the screen.
-
struct flanterm_fb_char empty;
-
empty.c = ' ';
-
empty.fg = ctx->text_fg;
-
empty.bg = ctx->text_bg;
-
for (size_t i = 0; i < _ctx->cols; i++) {
-
push_to_queue(_ctx, &empty, i, _ctx->scroll_top_margin);
-
}
-
}
-
-
static void flanterm_fb_scroll(struct flanterm_context *_ctx) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
for (size_t i = (_ctx->scroll_top_margin + 1) * _ctx->cols;
-
i < _ctx->scroll_bottom_margin * _ctx->cols; i++) {
-
struct flanterm_fb_char *c;
-
struct flanterm_fb_queue_item *q = ctx->map[i];
-
if (q != NULL) {
-
c = &q->c;
-
} else {
-
c = &ctx->grid[i];
-
}
-
push_to_queue(_ctx, c, (i - _ctx->cols) % _ctx->cols, (i - _ctx->cols) / _ctx->cols);
-
}
-
-
// Clear the last line of the screen.
-
struct flanterm_fb_char empty;
-
empty.c = ' ';
-
empty.fg = ctx->text_fg;
-
empty.bg = ctx->text_bg;
-
for (size_t i = 0; i < _ctx->cols; i++) {
-
push_to_queue(_ctx, &empty, i, _ctx->scroll_bottom_margin - 1);
-
}
-
}
-
-
static void flanterm_fb_clear(struct flanterm_context *_ctx, bool move) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
struct flanterm_fb_char empty;
-
empty.c = ' ';
-
empty.fg = ctx->text_fg;
-
empty.bg = ctx->text_bg;
-
for (size_t i = 0; i < _ctx->rows * _ctx->cols; i++) {
-
push_to_queue(_ctx, &empty, i % _ctx->cols, i / _ctx->cols);
-
}
-
-
if (move) {
-
ctx->cursor_x = 0;
-
ctx->cursor_y = 0;
-
}
-
}
-
-
static void flanterm_fb_set_cursor_pos(struct flanterm_context *_ctx, size_t x, size_t y) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
if (x >= _ctx->cols) {
-
if ((int)x < 0) {
-
x = 0;
-
} else {
-
x = _ctx->cols - 1;
-
}
-
}
-
if (y >= _ctx->rows) {
-
if ((int)y < 0) {
-
y = 0;
-
} else {
-
y = _ctx->rows - 1;
-
}
-
}
-
ctx->cursor_x = x;
-
ctx->cursor_y = y;
-
}
-
-
static void flanterm_fb_get_cursor_pos(struct flanterm_context *_ctx, size_t *x, size_t *y) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
*x = ctx->cursor_x >= _ctx->cols ? _ctx->cols - 1 : ctx->cursor_x;
-
*y = ctx->cursor_y >= _ctx->rows ? _ctx->rows - 1 : ctx->cursor_y;
-
}
-
-
static void flanterm_fb_move_character(struct flanterm_context *_ctx, size_t new_x, size_t new_y, size_t old_x, size_t old_y) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
if (old_x >= _ctx->cols || old_y >= _ctx->rows
-
|| new_x >= _ctx->cols || new_y >= _ctx->rows) {
-
return;
-
}
-
-
size_t i = old_x + old_y * _ctx->cols;
-
-
struct flanterm_fb_char *c;
-
struct flanterm_fb_queue_item *q = ctx->map[i];
-
if (q != NULL) {
-
c = &q->c;
-
} else {
-
c = &ctx->grid[i];
-
}
-
-
push_to_queue(_ctx, c, new_x, new_y);
-
}
-
-
static void flanterm_fb_set_text_fg(struct flanterm_context *_ctx, size_t fg) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
ctx->text_fg = ctx->ansi_colours[fg];
-
}
-
-
static void flanterm_fb_set_text_bg(struct flanterm_context *_ctx, size_t bg) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
ctx->text_bg = ctx->ansi_colours[bg];
-
}
-
-
static void flanterm_fb_set_text_fg_bright(struct flanterm_context *_ctx, size_t fg) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
ctx->text_fg = ctx->ansi_bright_colours[fg];
-
}
-
-
static void flanterm_fb_set_text_bg_bright(struct flanterm_context *_ctx, size_t bg) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
ctx->text_bg = ctx->ansi_bright_colours[bg];
-
}
-
-
static void flanterm_fb_set_text_fg_rgb(struct flanterm_context *_ctx, uint32_t fg) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
ctx->text_fg = convert_colour(_ctx, fg);
-
}
-
-
static void flanterm_fb_set_text_bg_rgb(struct flanterm_context *_ctx, uint32_t bg) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
ctx->text_bg = convert_colour(_ctx, bg);
-
}
-
-
static void flanterm_fb_set_text_fg_default(struct flanterm_context *_ctx) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
ctx->text_fg = ctx->default_fg;
-
}
-
-
static void flanterm_fb_set_text_bg_default(struct flanterm_context *_ctx) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
ctx->text_bg = 0xffffffff;
-
}
-
-
static void flanterm_fb_set_text_fg_default_bright(struct flanterm_context *_ctx) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
ctx->text_fg = ctx->default_fg_bright;
-
}
-
-
static void flanterm_fb_set_text_bg_default_bright(struct flanterm_context *_ctx) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
ctx->text_bg = ctx->default_bg_bright;
-
}
-
-
static void draw_cursor(struct flanterm_context *_ctx) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
if (ctx->cursor_x >= _ctx->cols || ctx->cursor_y >= _ctx->rows) {
-
return;
-
}
-
-
size_t i = ctx->cursor_x + ctx->cursor_y * _ctx->cols;
-
-
struct flanterm_fb_char c;
-
struct flanterm_fb_queue_item *q = ctx->map[i];
-
if (q != NULL) {
-
c = q->c;
-
} else {
-
c = ctx->grid[i];
-
}
-
uint32_t tmp = c.fg;
-
c.fg = c.bg;
-
c.bg = tmp;
-
plot_char(_ctx, &c, ctx->cursor_x, ctx->cursor_y);
-
if (q != NULL) {
-
ctx->grid[i] = q->c;
-
ctx->map[i] = NULL;
-
}
-
}
-
-
static void flanterm_fb_double_buffer_flush(struct flanterm_context *_ctx) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
if (_ctx->cursor_enabled) {
-
draw_cursor(_ctx);
-
}
-
-
for (size_t i = 0; i < ctx->queue_i; i++) {
-
struct flanterm_fb_queue_item *q = &ctx->queue[i];
-
size_t offset = q->y * _ctx->cols + q->x;
-
if (ctx->map[offset] == NULL) {
-
continue;
-
}
-
struct flanterm_fb_char *old = &ctx->grid[offset];
-
if (q->c.bg == old->bg && q->c.fg == old->fg) {
-
plot_char_fast(_ctx, old, &q->c, q->x, q->y);
-
} else {
-
plot_char(_ctx, &q->c, q->x, q->y);
-
}
-
ctx->grid[offset] = q->c;
-
ctx->map[offset] = NULL;
-
}
-
-
if ((ctx->old_cursor_x != ctx->cursor_x || ctx->old_cursor_y != ctx->cursor_y) || _ctx->cursor_enabled == false) {
-
if (ctx->old_cursor_x < _ctx->cols && ctx->old_cursor_y < _ctx->rows) {
-
plot_char(_ctx, &ctx->grid[ctx->old_cursor_x + ctx->old_cursor_y * _ctx->cols], ctx->old_cursor_x, ctx->old_cursor_y);
-
}
-
}
-
-
ctx->old_cursor_x = ctx->cursor_x;
-
ctx->old_cursor_y = ctx->cursor_y;
-
-
ctx->queue_i = 0;
-
}
-
-
static void flanterm_fb_raw_putchar(struct flanterm_context *_ctx, uint8_t c) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
if (ctx->cursor_x >= _ctx->cols && (ctx->cursor_y < _ctx->scroll_bottom_margin - 1 || _ctx->scroll_enabled)) {
-
ctx->cursor_x = 0;
-
ctx->cursor_y++;
-
if (ctx->cursor_y == _ctx->scroll_bottom_margin) {
-
ctx->cursor_y--;
-
flanterm_fb_scroll(_ctx);
-
}
-
if (ctx->cursor_y >= _ctx->cols) {
-
ctx->cursor_y = _ctx->cols - 1;
-
}
-
}
-
-
struct flanterm_fb_char ch;
-
ch.c = c;
-
ch.fg = ctx->text_fg;
-
ch.bg = ctx->text_bg;
-
push_to_queue(_ctx, &ch, ctx->cursor_x++, ctx->cursor_y);
-
}
-
-
static void flanterm_fb_full_refresh(struct flanterm_context *_ctx) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
#ifdef FLANTERM_FB_DISABLE_CANVAS
-
uint32_t default_bg = ctx->default_bg;
-
#endif
-
-
for (size_t y = 0; y < ctx->height; y++) {
-
for (size_t x = 0; x < ctx->width; x++) {
-
#ifndef FLANTERM_FB_DISABLE_CANVAS
-
ctx->framebuffer[y * (ctx->pitch / sizeof(uint32_t)) + x] = ctx->canvas[y * ctx->width + x];
-
#else
-
ctx->framebuffer[y * (ctx->pitch / sizeof(uint32_t)) + x] = default_bg;
-
#endif
-
}
-
}
-
-
for (size_t i = 0; i < (size_t)_ctx->rows * _ctx->cols; i++) {
-
size_t x = i % _ctx->cols;
-
size_t y = i / _ctx->cols;
-
-
plot_char(_ctx, &ctx->grid[i], x, y);
-
}
-
-
if (_ctx->cursor_enabled) {
-
draw_cursor(_ctx);
-
}
-
}
-
-
static void flanterm_fb_deinit(struct flanterm_context *_ctx, void (*_free)(void *, size_t)) {
-
struct flanterm_fb_context *ctx = (void *)_ctx;
-
-
if (_free == NULL) {
-
return;
-
}
-
-
_free(ctx->font_bits, ctx->font_bits_size);
-
_free(ctx->font_bool, ctx->font_bool_size);
-
_free(ctx->grid, ctx->grid_size);
-
_free(ctx->queue, ctx->queue_size);
-
_free(ctx->map, ctx->map_size);
-
-
#ifndef FLANTERM_FB_DISABLE_CANVAS
-
_free(ctx->canvas, ctx->canvas_size);
-
#endif
-
-
_free(ctx, sizeof(struct flanterm_fb_context));
-
}
-
-
struct flanterm_context *flanterm_fb_init(
-
void *(*_malloc)(size_t),
-
void (*_free)(void *, size_t),
-
uint32_t *framebuffer, size_t width, size_t height, size_t pitch,
-
#ifdef FLANTERM_FB_SUPPORT_BPP
-
uint8_t red_mask_size, uint8_t red_mask_shift,
-
uint8_t green_mask_size, uint8_t green_mask_shift,
-
uint8_t blue_mask_size, uint8_t blue_mask_shift,
-
#endif
-
#ifndef FLANTERM_FB_DISABLE_CANVAS
-
uint32_t *canvas,
-
#endif
-
uint32_t *ansi_colours, uint32_t *ansi_bright_colours,
-
uint32_t *default_bg, uint32_t *default_fg,
-
uint32_t *default_bg_bright, uint32_t *default_fg_bright,
-
void *font, size_t font_width, size_t font_height, size_t font_spacing,
-
size_t font_scale_x, size_t font_scale_y,
-
size_t margin
-
) {
-
#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
-
size_t orig_bump_alloc_ptr = bump_alloc_ptr;
-
#endif
-
-
#ifdef FLANTERM_FB_SUPPORT_BPP
-
if (red_mask_size < 8 || red_mask_size != green_mask_size || red_mask_size != blue_mask_size) {
-
return NULL;
-
}
-
#endif
-
-
if (_malloc == NULL) {
-
#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
-
_malloc = bump_alloc;
-
#else
-
return NULL;
-
#endif
-
}
-
-
struct flanterm_fb_context *ctx = NULL;
-
ctx = _malloc(sizeof(struct flanterm_fb_context));
-
if (ctx == NULL) {
-
goto fail;
-
}
-
-
struct flanterm_context *_ctx = (void *)ctx;
-
memset(ctx, 0, sizeof(struct flanterm_fb_context));
-
-
#ifdef FLANTERM_FB_SUPPORT_BPP
-
ctx->red_mask_size = red_mask_size;
-
ctx->red_mask_shift = red_mask_shift + (red_mask_size - 8);
-
ctx->green_mask_size = green_mask_size;
-
ctx->green_mask_shift = green_mask_shift + (green_mask_size - 8);
-
ctx->blue_mask_size = blue_mask_size;
-
ctx->blue_mask_shift = blue_mask_shift + (blue_mask_size - 8);
-
#endif
-
-
if (ansi_colours != NULL) {
-
for (size_t i = 0; i < 8; i++) {
-
ctx->ansi_colours[i] = convert_colour(_ctx, ansi_colours[i]);
-
}
-
} else {
-
ctx->ansi_colours[0] = convert_colour(_ctx, 0x00000000); // black
-
ctx->ansi_colours[1] = convert_colour(_ctx, 0x00aa0000); // red
-
ctx->ansi_colours[2] = convert_colour(_ctx, 0x0000aa00); // green
-
ctx->ansi_colours[3] = convert_colour(_ctx, 0x00aa5500); // brown
-
ctx->ansi_colours[4] = convert_colour(_ctx, 0x000000aa); // blue
-
ctx->ansi_colours[5] = convert_colour(_ctx, 0x00aa00aa); // magenta
-
ctx->ansi_colours[6] = convert_colour(_ctx, 0x0000aaaa); // cyan
-
ctx->ansi_colours[7] = convert_colour(_ctx, 0x00aaaaaa); // grey
-
}
-
-
if (ansi_bright_colours != NULL) {
-
for (size_t i = 0; i < 8; i++) {
-
ctx->ansi_bright_colours[i] = convert_colour(_ctx, ansi_bright_colours[i]);
-
}
-
} else {
-
ctx->ansi_bright_colours[0] = convert_colour(_ctx, 0x00555555); // black
-
ctx->ansi_bright_colours[1] = convert_colour(_ctx, 0x00ff5555); // red
-
ctx->ansi_bright_colours[2] = convert_colour(_ctx, 0x0055ff55); // green
-
ctx->ansi_bright_colours[3] = convert_colour(_ctx, 0x00ffff55); // brown
-
ctx->ansi_bright_colours[4] = convert_colour(_ctx, 0x005555ff); // blue
-
ctx->ansi_bright_colours[5] = convert_colour(_ctx, 0x00ff55ff); // magenta
-
ctx->ansi_bright_colours[6] = convert_colour(_ctx, 0x0055ffff); // cyan
-
ctx->ansi_bright_colours[7] = convert_colour(_ctx, 0x00ffffff); // grey
-
}
-
-
if (default_bg != NULL) {
-
ctx->default_bg = convert_colour(_ctx, *default_bg);
-
} else {
-
ctx->default_bg = 0x00000000; // background (black)
-
}
-
-
if (default_fg != NULL) {
-
ctx->default_fg = convert_colour(_ctx, *default_fg);
-
} else {
-
ctx->default_fg = convert_colour(_ctx, 0x00aaaaaa); // foreground (grey)
-
}
-
-
if (default_bg_bright != NULL) {
-
ctx->default_bg_bright = convert_colour(_ctx, *default_bg_bright);
-
} else {
-
ctx->default_bg_bright = convert_colour(_ctx, 0x00555555); // background (black)
-
}
-
-
if (default_fg_bright != NULL) {
-
ctx->default_fg_bright = convert_colour(_ctx, *default_fg_bright);
-
} else {
-
ctx->default_fg_bright = convert_colour(_ctx, 0x00ffffff); // foreground (grey)
-
}
-
-
ctx->text_fg = ctx->default_fg;
-
ctx->text_bg = 0xffffffff;
-
-
ctx->framebuffer = (void *)framebuffer;
-
ctx->width = width;
-
ctx->height = height;
-
ctx->pitch = pitch;
-
-
#define FONT_BYTES ((font_width * font_height * FLANTERM_FB_FONT_GLYPHS) / 8)
-
-
if (font != NULL) {
-
ctx->font_width = font_width;
-
ctx->font_height = font_height;
-
ctx->font_bits_size = FONT_BYTES;
-
ctx->font_bits = _malloc(ctx->font_bits_size);
-
if (ctx->font_bits == NULL) {
-
goto fail;
-
}
-
memcpy(ctx->font_bits, font, ctx->font_bits_size);
-
} else {
-
ctx->font_width = font_width = 8;
-
ctx->font_height = font_height = 16;
-
ctx->font_bits_size = FONT_BYTES;
-
font_spacing = 1;
-
ctx->font_bits = _malloc(ctx->font_bits_size);
-
if (ctx->font_bits == NULL) {
-
goto fail;
-
}
-
memcpy(ctx->font_bits, builtin_font, ctx->font_bits_size);
-
}
-
-
#undef FONT_BYTES
-
-
ctx->font_width += font_spacing;
-
-
ctx->font_bool_size = FLANTERM_FB_FONT_GLYPHS * font_height * ctx->font_width * sizeof(bool);
-
ctx->font_bool = _malloc(ctx->font_bool_size);
-
if (ctx->font_bool == NULL) {
-
goto fail;
-
}
-
-
for (size_t i = 0; i < FLANTERM_FB_FONT_GLYPHS; i++) {
-
uint8_t *glyph = &ctx->font_bits[i * font_height];
-
-
for (size_t y = 0; y < font_height; y++) {
-
// NOTE: the characters in VGA fonts are always one byte wide.
-
// 9 dot wide fonts have 8 dots and one empty column, except
-
// characters 0xC0-0xDF replicate column 9.
-
for (size_t x = 0; x < 8; x++) {
-
size_t offset = i * font_height * ctx->font_width + y * ctx->font_width + x;
-
-
if ((glyph[y] & (0x80 >> x))) {
-
ctx->font_bool[offset] = true;
-
} else {
-
ctx->font_bool[offset] = false;
-
}
-
}
-
// fill columns above 8 like VGA Line Graphics Mode does
-
for (size_t x = 8; x < ctx->font_width; x++) {
-
size_t offset = i * font_height * ctx->font_width + y * ctx->font_width + x;
-
-
if (i >= 0xc0 && i <= 0xdf) {
-
ctx->font_bool[offset] = (glyph[y] & 1);
-
} else {
-
ctx->font_bool[offset] = false;
-
}
-
}
-
}
-
}
-
-
ctx->font_scale_x = font_scale_x;
-
ctx->font_scale_y = font_scale_y;
-
-
ctx->glyph_width = ctx->font_width * font_scale_x;
-
ctx->glyph_height = font_height * font_scale_y;
-
-
_ctx->cols = (ctx->width - margin * 2) / ctx->glyph_width;
-
_ctx->rows = (ctx->height - margin * 2) / ctx->glyph_height;
-
-
ctx->offset_x = margin + ((ctx->width - margin * 2) % ctx->glyph_width) / 2;
-
ctx->offset_y = margin + ((ctx->height - margin * 2) % ctx->glyph_height) / 2;
-
-
ctx->grid_size = _ctx->rows * _ctx->cols * sizeof(struct flanterm_fb_char);
-
ctx->grid = _malloc(ctx->grid_size);
-
if (ctx->grid == NULL) {
-
goto fail;
-
}
-
for (size_t i = 0; i < _ctx->rows * _ctx->cols; i++) {
-
ctx->grid[i].c = ' ';
-
ctx->grid[i].fg = ctx->text_fg;
-
ctx->grid[i].bg = ctx->text_bg;
-
}
-
-
ctx->queue_size = _ctx->rows * _ctx->cols * sizeof(struct flanterm_fb_queue_item);
-
ctx->queue = _malloc(ctx->queue_size);
-
if (ctx->queue == NULL) {
-
goto fail;
-
}
-
ctx->queue_i = 0;
-
memset(ctx->queue, 0, ctx->queue_size);
-
-
ctx->map_size = _ctx->rows * _ctx->cols * sizeof(struct flanterm_fb_queue_item *);
-
ctx->map = _malloc(ctx->map_size);
-
if (ctx->map == NULL) {
-
goto fail;
-
}
-
memset(ctx->map, 0, ctx->map_size);
-
-
#ifndef FLANTERM_FB_DISABLE_CANVAS
-
ctx->canvas_size = ctx->width * ctx->height * sizeof(uint32_t);
-
ctx->canvas = _malloc(ctx->canvas_size);
-
if (ctx->canvas == NULL) {
-
goto fail;
-
}
-
if (canvas != NULL) {
-
for (size_t i = 0; i < ctx->width * ctx->height; i++) {
-
ctx->canvas[i] = convert_colour(_ctx, canvas[i]);
-
}
-
} else {
-
for (size_t i = 0; i < ctx->width * ctx->height; i++) {
-
ctx->canvas[i] = ctx->default_bg;
-
}
-
}
-
#endif
-
-
_ctx->raw_putchar = flanterm_fb_raw_putchar;
-
_ctx->clear = flanterm_fb_clear;
-
_ctx->set_cursor_pos = flanterm_fb_set_cursor_pos;
-
_ctx->get_cursor_pos = flanterm_fb_get_cursor_pos;
-
_ctx->set_text_fg = flanterm_fb_set_text_fg;
-
_ctx->set_text_bg = flanterm_fb_set_text_bg;
-
_ctx->set_text_fg_bright = flanterm_fb_set_text_fg_bright;
-
_ctx->set_text_bg_bright = flanterm_fb_set_text_bg_bright;
-
_ctx->set_text_fg_rgb = flanterm_fb_set_text_fg_rgb;
-
_ctx->set_text_bg_rgb = flanterm_fb_set_text_bg_rgb;
-
_ctx->set_text_fg_default = flanterm_fb_set_text_fg_default;
-
_ctx->set_text_bg_default = flanterm_fb_set_text_bg_default;
-
_ctx->set_text_fg_default_bright = flanterm_fb_set_text_fg_default_bright;
-
_ctx->set_text_bg_default_bright = flanterm_fb_set_text_bg_default_bright;
-
_ctx->move_character = flanterm_fb_move_character;
-
_ctx->scroll = flanterm_fb_scroll;
-
_ctx->revscroll = flanterm_fb_revscroll;
-
_ctx->swap_palette = flanterm_fb_swap_palette;
-
_ctx->save_state = flanterm_fb_save_state;
-
_ctx->restore_state = flanterm_fb_restore_state;
-
_ctx->double_buffer_flush = flanterm_fb_double_buffer_flush;
-
_ctx->full_refresh = flanterm_fb_full_refresh;
-
_ctx->deinit = flanterm_fb_deinit;
-
-
flanterm_context_reinit(_ctx);
-
flanterm_fb_full_refresh(_ctx);
-
-
return _ctx;
-
-
fail:
-
#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
-
if (_malloc == bump_alloc) {
-
bump_alloc_ptr = orig_bump_alloc_ptr;
-
return NULL;
-
}
-
#endif
-
-
if (_free == NULL) {
-
return NULL;
-
}
-
-
#ifndef FLANTERM_FB_DISABLE_CANVAS
-
if (ctx->canvas != NULL) {
-
_free(ctx->canvas, ctx->canvas_size);
-
}
-
#endif
-
if (ctx->map != NULL) {
-
_free(ctx->map, ctx->map_size);
-
}
-
if (ctx->queue != NULL) {
-
_free(ctx->queue, ctx->queue_size);
-
}
-
if (ctx->grid != NULL) {
-
_free(ctx->grid, ctx->grid_size);
-
}
-
if (ctx->font_bool != NULL) {
-
_free(ctx->font_bool, ctx->font_bool_size);
-
}
-
if (ctx->font_bits != NULL) {
-
_free(ctx->font_bits, ctx->font_bits_size);
-
}
-
if (ctx != NULL) {
-
_free(ctx, sizeof(struct flanterm_fb_context));
-
}
-
-
return NULL;
-
}
-184
backends/fb.h
···
-
/* Copyright (C) 2022-2023 mintsuki and contributors.
-
*
-
* Redistribution and use in source and binary forms, with or without
-
* modification, are permitted provided that the following conditions are met:
-
*
-
* 1. Redistributions of source code must retain the above copyright notice,
-
* this list of conditions and the following disclaimer.
-
*
-
* 2. Redistributions in binary form must reproduce the above copyright notice,
-
* this list of conditions and the following disclaimer in the documentation
-
* and/or other materials provided with the distribution.
-
*
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
-
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-
* POSSIBILITY OF SUCH DAMAGE.
-
*/
-
-
#ifndef _FLANTERM_FR_H
-
#define _FLANTERM_FB_H 1
-
-
#ifdef __cplusplus
-
extern "C" {
-
#endif
-
-
#include <stdint.h>
-
#include <stddef.h>
-
#include <stdbool.h>
-
-
#include "../flanterm.h"
-
-
#define FLANTERM_FB_FONT_GLYPHS 256
-
-
struct flanterm_fb_char {
-
uint32_t c;
-
uint32_t fg;
-
uint32_t bg;
-
};
-
-
struct flanterm_fb_queue_item {
-
size_t x, y;
-
struct flanterm_fb_char c;
-
};
-
-
struct flanterm_fb_context {
-
struct flanterm_context term;
-
-
size_t font_width;
-
size_t font_height;
-
size_t glyph_width;
-
size_t glyph_height;
-
-
size_t font_scale_x;
-
size_t font_scale_y;
-
-
size_t offset_x, offset_y;
-
-
volatile uint32_t *framebuffer;
-
size_t pitch;
-
size_t width;
-
size_t height;
-
size_t bpp;
-
-
#ifdef FLANTERM_FB_SUPPORT_BPP
-
uint8_t red_mask_size, red_mask_shift;
-
uint8_t green_mask_size, green_mask_shift;
-
uint8_t blue_mask_size, blue_mask_shift;
-
#endif
-
-
size_t font_bits_size;
-
uint8_t *font_bits;
-
size_t font_bool_size;
-
bool *font_bool;
-
-
uint32_t ansi_colours[8];
-
uint32_t ansi_bright_colours[8];
-
uint32_t default_fg, default_bg;
-
uint32_t default_fg_bright, default_bg_bright;
-
-
#ifndef FLANTERM_FB_DISABLE_CANVAS
-
size_t canvas_size;
-
uint32_t *canvas;
-
#endif
-
-
size_t grid_size;
-
size_t queue_size;
-
size_t map_size;
-
-
struct flanterm_fb_char *grid;
-
-
struct flanterm_fb_queue_item *queue;
-
size_t queue_i;
-
-
struct flanterm_fb_queue_item **map;
-
-
uint32_t text_fg;
-
uint32_t text_bg;
-
size_t cursor_x;
-
size_t cursor_y;
-
-
uint32_t saved_state_text_fg;
-
uint32_t saved_state_text_bg;
-
size_t saved_state_cursor_x;
-
size_t saved_state_cursor_y;
-
-
size_t old_cursor_x;
-
size_t old_cursor_y;
-
};
-
-
struct flanterm_context *flanterm_fb_init(
-
void *(*_malloc)(size_t),
-
void (*_free)(void *, size_t),
-
uint32_t *framebuffer, size_t width, size_t height, size_t pitch,
-
#ifdef FLANTERM_FB_SUPPORT_BPP
-
uint8_t red_mask_size, uint8_t red_mask_shift,
-
uint8_t green_mask_size, uint8_t green_mask_shift,
-
uint8_t blue_mask_size, uint8_t blue_mask_shift,
-
#endif
-
#ifndef FLANTERM_FB_DISABLE_CANVAS
-
uint32_t *canvas,
-
#endif
-
uint32_t *ansi_colours, uint32_t *ansi_bright_colours,
-
uint32_t *default_bg, uint32_t *default_fg,
-
uint32_t *default_bg_bright, uint32_t *default_fg_bright,
-
void *font, size_t font_width, size_t font_height, size_t font_spacing,
-
size_t font_scale_x, size_t font_scale_y,
-
size_t margin
-
);
-
-
#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
-
static inline struct flanterm_context *flanterm_fb_simple_init(
-
uint32_t *framebuffer, size_t width, size_t height, size_t pitch
-
#ifdef FLANTERM_FB_SUPPORT_BPP
-
,
-
uint8_t red_mask_size, uint8_t red_mask_shift,
-
uint8_t green_mask_size, uint8_t green_mask_shift,
-
uint8_t blue_mask_size, uint8_t blue_mask_shift
-
#endif
-
) {
-
size_t font_scale_x = 1;
-
size_t font_scale_y = 1;
-
if (width >= (1920 + 1920 / 3) && height >= (1080 + 1080 / 3)) {
-
font_scale_x = 2;
-
font_scale_y = 2;
-
}
-
if (width >= (3840 + 3840 / 3) && height >= (2160 + 2160 / 3)) {
-
font_scale_x = 4;
-
font_scale_y = 4;
-
}
-
-
return flanterm_fb_init(
-
NULL,
-
NULL,
-
framebuffer, width, height, pitch,
-
#ifdef FLANTERM_FB_SUPPORT_BPP
-
red_mask_size, red_mask_shift,
-
green_mask_size, green_mask_shift,
-
blue_mask_size, blue_mask_shift,
-
#endif
-
#ifndef FLANTERM_FB_DISABLE_CANVAS
-
NULL,
-
#endif
-
NULL, NULL,
-
NULL, NULL,
-
NULL, NULL,
-
NULL, 0, 0, 1,
-
font_scale_x, font_scale_y,
-
0
-
);
-
}
-
#endif
-
-
#ifdef __cplusplus
-
}
-
#endif
-
-
#endif
+17
build.zig
···
+
const std = @import("std");
+
+
pub fn build(b: *std.Build) void {
+
// Create the exported module
+
const mod = b.addModule("flanterm", .{
+
.root_source_file = b.path("src/root.zig"),
+
});
+
+
// Add the C source files and includes
+
mod.addIncludePath(b.path("src"));
+
mod.addCSourceFiles(.{
+
.files = &.{
+
"src/flanterm.c",
+
"src/flanterm_backends/fb.c",
+
},
+
});
+
}
+15
build.zig.zon
···
+
.{
+
.name = .flanterm,
+
.version = "2.0.0",
+
.fingerprint = 0x5e517d869e9f7b42, // Changing this has security and trust implications.
+
.minimum_zig_version = "0.15.1",
+
.dependencies = .{},
+
.paths = .{
+
"build.zig",
+
"build.zig.zon",
+
"src",
+
"LICENSE",
+
"README.md",
+
".gitignore",
+
},
+
}
-1350
flanterm.c
···
-
/* Copyright (C) 2022-2023 mintsuki and contributors.
-
*
-
* Redistribution and use in source and binary forms, with or without
-
* modification, are permitted provided that the following conditions are met:
-
*
-
* 1. Redistributions of source code must retain the above copyright notice,
-
* this list of conditions and the following disclaimer.
-
*
-
* 2. Redistributions in binary form must reproduce the above copyright notice,
-
* this list of conditions and the following disclaimer in the documentation
-
* and/or other materials provided with the distribution.
-
*
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
-
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-
* POSSIBILITY OF SUCH DAMAGE.
-
*/
-
-
#include <stdint.h>
-
#include <stddef.h>
-
#include <stdbool.h>
-
-
#include "flanterm.h"
-
-
// Tries to implement this standard for terminfo
-
// https://man7.org/linux/man-pages/man4/console_codes.4.html
-
-
static const uint32_t col256[] = {
-
0x000000, 0x00005f, 0x000087, 0x0000af, 0x0000d7, 0x0000ff, 0x005f00, 0x005f5f,
-
0x005f87, 0x005faf, 0x005fd7, 0x005fff, 0x008700, 0x00875f, 0x008787, 0x0087af,
-
0x0087d7, 0x0087ff, 0x00af00, 0x00af5f, 0x00af87, 0x00afaf, 0x00afd7, 0x00afff,
-
0x00d700, 0x00d75f, 0x00d787, 0x00d7af, 0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f,
-
0x00ff87, 0x00ffaf, 0x00ffd7, 0x00ffff, 0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af,
-
0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f, 0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff,
-
0x5f8700, 0x5f875f, 0x5f8787, 0x5f87af, 0x5f87d7, 0x5f87ff, 0x5faf00, 0x5faf5f,
-
0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff, 0x5fd700, 0x5fd75f, 0x5fd787, 0x5fd7af,
-
0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f, 0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff,
-
0x870000, 0x87005f, 0x870087, 0x8700af, 0x8700d7, 0x8700ff, 0x875f00, 0x875f5f,
-
0x875f87, 0x875faf, 0x875fd7, 0x875fff, 0x878700, 0x87875f, 0x878787, 0x8787af,
-
0x8787d7, 0x8787ff, 0x87af00, 0x87af5f, 0x87af87, 0x87afaf, 0x87afd7, 0x87afff,
-
0x87d700, 0x87d75f, 0x87d787, 0x87d7af, 0x87d7d7, 0x87d7ff, 0x87ff00, 0x87ff5f,
-
0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff, 0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af,
-
0xaf00d7, 0xaf00ff, 0xaf5f00, 0xaf5f5f, 0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff,
-
0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af, 0xaf87d7, 0xaf87ff, 0xafaf00, 0xafaf5f,
-
0xafaf87, 0xafafaf, 0xafafd7, 0xafafff, 0xafd700, 0xafd75f, 0xafd787, 0xafd7af,
-
0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f, 0xafff87, 0xafffaf, 0xafffd7, 0xafffff,
-
0xd70000, 0xd7005f, 0xd70087, 0xd700af, 0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f,
-
0xd75f87, 0xd75faf, 0xd75fd7, 0xd75fff, 0xd78700, 0xd7875f, 0xd78787, 0xd787af,
-
0xd787d7, 0xd787ff, 0xd7af00, 0xd7af5f, 0xd7af87, 0xd7afaf, 0xd7afd7, 0xd7afff,
-
0xd7d700, 0xd7d75f, 0xd7d787, 0xd7d7af, 0xd7d7d7, 0xd7d7ff, 0xd7ff00, 0xd7ff5f,
-
0xd7ff87, 0xd7ffaf, 0xd7ffd7, 0xd7ffff, 0xff0000, 0xff005f, 0xff0087, 0xff00af,
-
0xff00d7, 0xff00ff, 0xff5f00, 0xff5f5f, 0xff5f87, 0xff5faf, 0xff5fd7, 0xff5fff,
-
0xff8700, 0xff875f, 0xff8787, 0xff87af, 0xff87d7, 0xff87ff, 0xffaf00, 0xffaf5f,
-
0xffaf87, 0xffafaf, 0xffafd7, 0xffafff, 0xffd700, 0xffd75f, 0xffd787, 0xffd7af,
-
0xffd7d7, 0xffd7ff, 0xffff00, 0xffff5f, 0xffff87, 0xffffaf, 0xffffd7, 0xffffff,
-
0x080808, 0x121212, 0x1c1c1c, 0x262626, 0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e,
-
0x585858, 0x626262, 0x6c6c6c, 0x767676, 0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e,
-
0xa8a8a8, 0xb2b2b2, 0xbcbcbc, 0xc6c6c6, 0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee
-
};
-
-
#define CHARSET_DEFAULT 0
-
#define CHARSET_DEC_SPECIAL 1
-
-
void flanterm_context_reinit(struct flanterm_context *ctx) {
-
ctx->tab_size = 8;
-
ctx->autoflush = true;
-
ctx->cursor_enabled = true;
-
ctx->scroll_enabled = true;
-
ctx->control_sequence = false;
-
ctx->csi = false;
-
ctx->escape = false;
-
ctx->osc = false;
-
ctx->osc_escape = false;
-
ctx->rrr = false;
-
ctx->discard_next = false;
-
ctx->bold = false;
-
ctx->bg_bold = false;
-
ctx->reverse_video = false;
-
ctx->dec_private = false;
-
ctx->insert_mode = false;
-
ctx->unicode_remaining = 0;
-
ctx->g_select = 0;
-
ctx->charsets[0] = CHARSET_DEFAULT;
-
ctx->charsets[1] = CHARSET_DEC_SPECIAL;
-
ctx->current_charset = 0;
-
ctx->escape_offset = 0;
-
ctx->esc_values_i = 0;
-
ctx->saved_cursor_x = 0;
-
ctx->saved_cursor_y = 0;
-
ctx->current_primary = (size_t)-1;
-
ctx->current_bg = (size_t)-1;
-
ctx->scroll_top_margin = 0;
-
ctx->scroll_bottom_margin = ctx->rows;
-
ctx->oob_output = FLANTERM_OOB_OUTPUT_ONLCR;
-
}
-
-
static void flanterm_putchar(struct flanterm_context *ctx, uint8_t c);
-
-
void flanterm_write(struct flanterm_context *ctx, const char *buf, size_t count) {
-
for (size_t i = 0; i < count; i++) {
-
flanterm_putchar(ctx, buf[i]);
-
}
-
-
if (ctx->autoflush) {
-
ctx->double_buffer_flush(ctx);
-
}
-
}
-
-
static void sgr(struct flanterm_context *ctx) {
-
size_t i = 0;
-
-
if (!ctx->esc_values_i)
-
goto def;
-
-
for (; i < ctx->esc_values_i; i++) {
-
size_t offset;
-
-
if (ctx->esc_values[i] == 0) {
-
def:
-
if (ctx->reverse_video) {
-
ctx->reverse_video = false;
-
ctx->swap_palette(ctx);
-
}
-
ctx->bold = false;
-
ctx->bg_bold = false;
-
ctx->current_primary = (size_t)-1;
-
ctx->current_bg = (size_t)-1;
-
ctx->set_text_bg_default(ctx);
-
ctx->set_text_fg_default(ctx);
-
continue;
-
}
-
-
else if (ctx->esc_values[i] == 1) {
-
ctx->bold = true;
-
if (ctx->current_primary != (size_t)-1) {
-
if (!ctx->reverse_video) {
-
ctx->set_text_fg_bright(ctx, ctx->current_primary);
-
} else {
-
ctx->set_text_bg_bright(ctx, ctx->current_primary);
-
}
-
} else {
-
if (!ctx->reverse_video) {
-
ctx->set_text_fg_default_bright(ctx);
-
} else {
-
ctx->set_text_bg_default_bright(ctx);
-
}
-
}
-
continue;
-
}
-
-
else if (ctx->esc_values[i] == 5) {
-
ctx->bg_bold = true;
-
if (ctx->current_bg != (size_t)-1) {
-
if (!ctx->reverse_video) {
-
ctx->set_text_bg_bright(ctx, ctx->current_bg);
-
} else {
-
ctx->set_text_fg_bright(ctx, ctx->current_bg);
-
}
-
} else {
-
if (!ctx->reverse_video) {
-
ctx->set_text_bg_default_bright(ctx);
-
} else {
-
ctx->set_text_fg_default_bright(ctx);
-
}
-
}
-
continue;
-
}
-
-
else if (ctx->esc_values[i] == 22) {
-
ctx->bold = false;
-
if (ctx->current_primary != (size_t)-1) {
-
if (!ctx->reverse_video) {
-
ctx->set_text_fg(ctx, ctx->current_primary);
-
} else {
-
ctx->set_text_bg(ctx, ctx->current_primary);
-
}
-
} else {
-
if (!ctx->reverse_video) {
-
ctx->set_text_fg_default(ctx);
-
} else {
-
ctx->set_text_bg_default(ctx);
-
}
-
}
-
continue;
-
}
-
-
else if (ctx->esc_values[i] == 25) {
-
ctx->bg_bold = false;
-
if (ctx->current_bg != (size_t)-1) {
-
if (!ctx->reverse_video) {
-
ctx->set_text_bg(ctx, ctx->current_bg);
-
} else {
-
ctx->set_text_fg(ctx, ctx->current_bg);
-
}
-
} else {
-
if (!ctx->reverse_video) {
-
ctx->set_text_bg_default(ctx);
-
} else {
-
ctx->set_text_fg_default(ctx);
-
}
-
}
-
continue;
-
}
-
-
else if (ctx->esc_values[i] >= 30 && ctx->esc_values[i] <= 37) {
-
offset = 30;
-
ctx->current_primary = ctx->esc_values[i] - offset;
-
-
if (ctx->reverse_video) {
-
goto set_bg;
-
}
-
-
set_fg:
-
if ((ctx->bold && !ctx->reverse_video)
-
|| (ctx->bg_bold && ctx->reverse_video)) {
-
ctx->set_text_fg_bright(ctx, ctx->esc_values[i] - offset);
-
} else {
-
ctx->set_text_fg(ctx, ctx->esc_values[i] - offset);
-
}
-
continue;
-
}
-
-
else if (ctx->esc_values[i] >= 40 && ctx->esc_values[i] <= 47) {
-
offset = 40;
-
ctx->current_bg = ctx->esc_values[i] - offset;
-
-
if (ctx->reverse_video) {
-
goto set_fg;
-
}
-
-
set_bg:
-
if ((ctx->bold && ctx->reverse_video)
-
|| (ctx->bg_bold && !ctx->reverse_video)) {
-
ctx->set_text_bg_bright(ctx, ctx->esc_values[i] - offset);
-
} else {
-
ctx->set_text_bg(ctx, ctx->esc_values[i] - offset);
-
}
-
continue;
-
}
-
-
else if (ctx->esc_values[i] >= 90 && ctx->esc_values[i] <= 97) {
-
offset = 90;
-
ctx->current_primary = ctx->esc_values[i] - offset;
-
-
if (ctx->reverse_video) {
-
goto set_bg_bright;
-
}
-
-
set_fg_bright:
-
ctx->set_text_fg_bright(ctx, ctx->esc_values[i] - offset);
-
continue;
-
}
-
-
else if (ctx->esc_values[i] >= 100 && ctx->esc_values[i] <= 107) {
-
offset = 100;
-
ctx->current_bg = ctx->esc_values[i] - offset;
-
-
if (ctx->reverse_video) {
-
goto set_fg_bright;
-
}
-
-
set_bg_bright:
-
ctx->set_text_bg_bright(ctx, ctx->esc_values[i] - offset);
-
continue;
-
}
-
-
else if (ctx->esc_values[i] == 39) {
-
ctx->current_primary = (size_t)-1;
-
-
if (ctx->reverse_video) {
-
ctx->swap_palette(ctx);
-
}
-
-
if (!ctx->bold) {
-
ctx->set_text_fg_default(ctx);
-
} else {
-
ctx->set_text_fg_default_bright(ctx);
-
}
-
-
if (ctx->reverse_video) {
-
ctx->swap_palette(ctx);
-
}
-
-
continue;
-
}
-
-
else if (ctx->esc_values[i] == 49) {
-
ctx->current_bg = (size_t)-1;
-
-
if (ctx->reverse_video) {
-
ctx->swap_palette(ctx);
-
}
-
-
if (!ctx->bg_bold) {
-
ctx->set_text_bg_default(ctx);
-
} else {
-
ctx->set_text_bg_default_bright(ctx);
-
}
-
-
if (ctx->reverse_video) {
-
ctx->swap_palette(ctx);
-
}
-
-
continue;
-
}
-
-
else if (ctx->esc_values[i] == 7) {
-
if (!ctx->reverse_video) {
-
ctx->reverse_video = true;
-
ctx->swap_palette(ctx);
-
}
-
continue;
-
}
-
-
else if (ctx->esc_values[i] == 27) {
-
if (ctx->reverse_video) {
-
ctx->reverse_video = false;
-
ctx->swap_palette(ctx);
-
}
-
continue;
-
}
-
-
// 256/RGB
-
else if (ctx->esc_values[i] == 38 || ctx->esc_values[i] == 48) {
-
bool fg = ctx->esc_values[i] == 38;
-
-
i++;
-
if (i >= ctx->esc_values_i) {
-
break;
-
}
-
-
switch (ctx->esc_values[i]) {
-
case 2: { // RGB
-
if (i + 3 >= ctx->esc_values_i) {
-
goto out;
-
}
-
-
uint32_t rgb_value = 0;
-
-
rgb_value |= ctx->esc_values[i + 1] << 16;
-
rgb_value |= ctx->esc_values[i + 2] << 8;
-
rgb_value |= ctx->esc_values[i + 3];
-
-
i += 3;
-
-
(fg ? ctx->set_text_fg_rgb : ctx->set_text_bg_rgb)(ctx, rgb_value);
-
-
break;
-
}
-
case 5: { // 256 colors
-
if (i + 1 >= ctx->esc_values_i) {
-
goto out;
-
}
-
-
uint32_t col = ctx->esc_values[i + 1];
-
-
i++;
-
-
if (col < 8) {
-
(fg ? ctx->set_text_fg : ctx->set_text_bg)(ctx, col);
-
} else if (col < 16) {
-
(fg ? ctx->set_text_fg_bright : ctx->set_text_bg_bright)(ctx, col - 8);
-
} else {
-
uint32_t rgb_value = col256[col - 16];
-
(fg ? ctx->set_text_fg_rgb : ctx->set_text_bg_rgb)(ctx, rgb_value);
-
}
-
-
break;
-
}
-
default: continue;
-
}
-
}
-
}
-
-
out:;
-
}
-
-
static void dec_private_parse(struct flanterm_context *ctx, uint8_t c) {
-
ctx->dec_private = false;
-
-
if (ctx->esc_values_i == 0) {
-
return;
-
}
-
-
bool set;
-
-
switch (c) {
-
case 'h':
-
set = true; break;
-
case 'l':
-
set = false; break;
-
default:
-
return;
-
}
-
-
switch (ctx->esc_values[0]) {
-
case 25: {
-
if (set) {
-
ctx->cursor_enabled = true;
-
} else {
-
ctx->cursor_enabled = false;
-
}
-
return;
-
}
-
}
-
-
if (ctx->callback != NULL) {
-
ctx->callback(ctx, FLANTERM_CB_DEC, ctx->esc_values_i, (uintptr_t)ctx->esc_values, c);
-
}
-
}
-
-
static void linux_private_parse(struct flanterm_context *ctx) {
-
if (ctx->esc_values_i == 0) {
-
return;
-
}
-
-
if (ctx->callback != NULL) {
-
ctx->callback(ctx, FLANTERM_CB_LINUX, ctx->esc_values_i, (uintptr_t)ctx->esc_values, 0);
-
}
-
}
-
-
static void mode_toggle(struct flanterm_context *ctx, uint8_t c) {
-
if (ctx->esc_values_i == 0) {
-
return;
-
}
-
-
bool set;
-
-
switch (c) {
-
case 'h':
-
set = true; break;
-
case 'l':
-
set = false; break;
-
default:
-
return;
-
}
-
-
switch (ctx->esc_values[0]) {
-
case 4:
-
ctx->insert_mode = set; return;
-
}
-
-
if (ctx->callback != NULL) {
-
ctx->callback(ctx, FLANTERM_CB_MODE, ctx->esc_values_i, (uintptr_t)ctx->esc_values, c);
-
}
-
}
-
-
static void osc_parse(struct flanterm_context *ctx, uint8_t c) {
-
if (ctx->osc_escape && c == '\\') {
-
goto cleanup;
-
}
-
-
ctx->osc_escape = false;
-
-
switch (c) {
-
case 0x1b:
-
ctx->osc_escape = true;
-
break;
-
case '\a':
-
goto cleanup;
-
}
-
-
return;
-
-
cleanup:
-
ctx->osc_escape = false;
-
ctx->osc = false;
-
ctx->escape = false;
-
}
-
-
static void control_sequence_parse(struct flanterm_context *ctx, uint8_t c) {
-
if (ctx->escape_offset == 2) {
-
switch (c) {
-
case '[':
-
ctx->discard_next = true;
-
goto cleanup;
-
case '?':
-
ctx->dec_private = true;
-
return;
-
}
-
}
-
-
if (c >= '0' && c <= '9') {
-
if (ctx->esc_values_i == FLANTERM_MAX_ESC_VALUES) {
-
return;
-
}
-
ctx->rrr = true;
-
ctx->esc_values[ctx->esc_values_i] *= 10;
-
ctx->esc_values[ctx->esc_values_i] += c - '0';
-
return;
-
}
-
-
if (ctx->rrr == true) {
-
ctx->esc_values_i++;
-
ctx->rrr = false;
-
if (c == ';')
-
return;
-
} else if (c == ';') {
-
if (ctx->esc_values_i == FLANTERM_MAX_ESC_VALUES) {
-
return;
-
}
-
ctx->esc_values[ctx->esc_values_i] = 0;
-
ctx->esc_values_i++;
-
return;
-
}
-
-
size_t esc_default;
-
switch (c) {
-
case 'J': case 'K': case 'q':
-
esc_default = 0; break;
-
default:
-
esc_default = 1; break;
-
}
-
-
for (size_t i = ctx->esc_values_i; i < FLANTERM_MAX_ESC_VALUES; i++) {
-
ctx->esc_values[i] = esc_default;
-
}
-
-
if (ctx->dec_private == true) {
-
dec_private_parse(ctx, c);
-
goto cleanup;
-
}
-
-
bool r = ctx->scroll_enabled;
-
ctx->scroll_enabled = false;
-
size_t x, y;
-
ctx->get_cursor_pos(ctx, &x, &y);
-
-
switch (c) {
-
case 'F':
-
x = 0;
-
// FALLTHRU
-
case 'A': {
-
if (ctx->esc_values[0] > y)
-
ctx->esc_values[0] = y;
-
size_t orig_y = y;
-
size_t dest_y = y - ctx->esc_values[0];
-
bool will_be_in_scroll_region = false;
-
if ((ctx->scroll_top_margin >= dest_y && ctx->scroll_top_margin <= orig_y)
-
|| (ctx->scroll_bottom_margin >= dest_y && ctx->scroll_bottom_margin <= orig_y)) {
-
will_be_in_scroll_region = true;
-
}
-
if (will_be_in_scroll_region && dest_y < ctx->scroll_top_margin) {
-
dest_y = ctx->scroll_top_margin;
-
}
-
ctx->set_cursor_pos(ctx, x, dest_y);
-
break;
-
}
-
case 'E':
-
x = 0;
-
// FALLTHRU
-
case 'e':
-
case 'B': {
-
if (y + ctx->esc_values[0] > ctx->rows - 1)
-
ctx->esc_values[0] = (ctx->rows - 1) - y;
-
size_t orig_y = y;
-
size_t dest_y = y + ctx->esc_values[0];
-
bool will_be_in_scroll_region = false;
-
if ((ctx->scroll_top_margin >= orig_y && ctx->scroll_top_margin <= dest_y)
-
|| (ctx->scroll_bottom_margin >= orig_y && ctx->scroll_bottom_margin <= dest_y)) {
-
will_be_in_scroll_region = true;
-
}
-
if (will_be_in_scroll_region && dest_y >= ctx->scroll_bottom_margin) {
-
dest_y = ctx->scroll_bottom_margin - 1;
-
}
-
ctx->set_cursor_pos(ctx, x, dest_y);
-
break;
-
}
-
case 'a':
-
case 'C':
-
if (x + ctx->esc_values[0] > ctx->cols - 1)
-
ctx->esc_values[0] = (ctx->cols - 1) - x;
-
ctx->set_cursor_pos(ctx, x + ctx->esc_values[0], y);
-
break;
-
case 'D':
-
if (ctx->esc_values[0] > x)
-
ctx->esc_values[0] = x;
-
ctx->set_cursor_pos(ctx, x - ctx->esc_values[0], y);
-
break;
-
case 'c':
-
if (ctx->callback != NULL) {
-
ctx->callback(ctx, FLANTERM_CB_PRIVATE_ID, 0, 0, 0);
-
}
-
break;
-
case 'd':
-
ctx->esc_values[0] -= 1;
-
if (ctx->esc_values[0] >= ctx->rows)
-
ctx->esc_values[0] = ctx->rows - 1;
-
ctx->set_cursor_pos(ctx, x, ctx->esc_values[0]);
-
break;
-
case 'G':
-
case '`':
-
ctx->esc_values[0] -= 1;
-
if (ctx->esc_values[0] >= ctx->cols)
-
ctx->esc_values[0] = ctx->cols - 1;
-
ctx->set_cursor_pos(ctx, ctx->esc_values[0], y);
-
break;
-
case 'H':
-
case 'f':
-
if (ctx->esc_values[0] != 0) {
-
ctx->esc_values[0]--;
-
}
-
if (ctx->esc_values[1] != 0) {
-
ctx->esc_values[1]--;
-
}
-
if (ctx->esc_values[1] >= ctx->cols)
-
ctx->esc_values[1] = ctx->cols - 1;
-
if (ctx->esc_values[0] >= ctx->rows)
-
ctx->esc_values[0] = ctx->rows - 1;
-
ctx->set_cursor_pos(ctx, ctx->esc_values[1], ctx->esc_values[0]);
-
break;
-
case 'M':
-
for (size_t i = 0; i < ctx->esc_values[0]; i++) {
-
ctx->scroll(ctx);
-
}
-
break;
-
case 'L': {
-
size_t old_scroll_top_margin = ctx->scroll_top_margin;
-
ctx->scroll_top_margin = y;
-
for (size_t i = 0; i < ctx->esc_values[0]; i++) {
-
ctx->revscroll(ctx);
-
}
-
ctx->scroll_top_margin = old_scroll_top_margin;
-
break;
-
}
-
case 'n':
-
switch (ctx->esc_values[0]) {
-
case 5:
-
if (ctx->callback != NULL) {
-
ctx->callback(ctx, FLANTERM_CB_STATUS_REPORT, 0, 0, 0);
-
}
-
break;
-
case 6:
-
if (ctx->callback != NULL) {
-
ctx->callback(ctx, FLANTERM_CB_POS_REPORT, x + 1, y + 1, 0);
-
}
-
break;
-
}
-
break;
-
case 'q':
-
if (ctx->callback != NULL) {
-
ctx->callback(ctx, FLANTERM_CB_KBD_LEDS, ctx->esc_values[0], 0, 0);
-
}
-
break;
-
case 'J':
-
switch (ctx->esc_values[0]) {
-
case 0: {
-
size_t rows_remaining = ctx->rows - (y + 1);
-
size_t cols_diff = ctx->cols - (x + 1);
-
size_t to_clear = rows_remaining * ctx->cols + cols_diff + 1;
-
for (size_t i = 0; i < to_clear; i++) {
-
ctx->raw_putchar(ctx, ' ');
-
}
-
ctx->set_cursor_pos(ctx, x, y);
-
break;
-
}
-
case 1: {
-
ctx->set_cursor_pos(ctx, 0, 0);
-
bool b = false;
-
for (size_t yc = 0; yc < ctx->rows; yc++) {
-
for (size_t xc = 0; xc < ctx->cols; xc++) {
-
ctx->raw_putchar(ctx, ' ');
-
if (xc == x && yc == y) {
-
ctx->set_cursor_pos(ctx, x, y);
-
b = true;
-
break;
-
}
-
}
-
if (b == true)
-
break;
-
}
-
break;
-
}
-
case 2:
-
case 3:
-
ctx->clear(ctx, false);
-
break;
-
}
-
break;
-
case '@':
-
for (size_t i = ctx->cols - 1; ; i--) {
-
ctx->move_character(ctx, i + ctx->esc_values[0], y, i, y);
-
ctx->set_cursor_pos(ctx, i, y);
-
ctx->raw_putchar(ctx, ' ');
-
if (i == x) {
-
break;
-
}
-
}
-
ctx->set_cursor_pos(ctx, x, y);
-
break;
-
case 'P':
-
for (size_t i = x + ctx->esc_values[0]; i < ctx->cols; i++)
-
ctx->move_character(ctx, i - ctx->esc_values[0], y, i, y);
-
ctx->set_cursor_pos(ctx, ctx->cols - ctx->esc_values[0], y);
-
// FALLTHRU
-
case 'X':
-
for (size_t i = 0; i < ctx->esc_values[0]; i++)
-
ctx->raw_putchar(ctx, ' ');
-
ctx->set_cursor_pos(ctx, x, y);
-
break;
-
case 'm':
-
sgr(ctx);
-
break;
-
case 's':
-
ctx->get_cursor_pos(ctx, &ctx->saved_cursor_x, &ctx->saved_cursor_y);
-
break;
-
case 'u':
-
ctx->set_cursor_pos(ctx, ctx->saved_cursor_x, ctx->saved_cursor_y);
-
break;
-
case 'K':
-
switch (ctx->esc_values[0]) {
-
case 0: {
-
for (size_t i = x; i < ctx->cols; i++)
-
ctx->raw_putchar(ctx, ' ');
-
ctx->set_cursor_pos(ctx, x, y);
-
break;
-
}
-
case 1: {
-
ctx->set_cursor_pos(ctx, 0, y);
-
for (size_t i = 0; i < x; i++)
-
ctx->raw_putchar(ctx, ' ');
-
break;
-
}
-
case 2: {
-
ctx->set_cursor_pos(ctx, 0, y);
-
for (size_t i = 0; i < ctx->cols; i++)
-
ctx->raw_putchar(ctx, ' ');
-
ctx->set_cursor_pos(ctx, x, y);
-
break;
-
}
-
}
-
break;
-
case 'r':
-
if (ctx->esc_values[0] == 0) {
-
ctx->esc_values[0] = 1;
-
}
-
if (ctx->esc_values[1] == 0) {
-
ctx->esc_values[1] = 1;
-
}
-
ctx->scroll_top_margin = 0;
-
ctx->scroll_bottom_margin = ctx->rows;
-
if (ctx->esc_values_i > 0) {
-
ctx->scroll_top_margin = ctx->esc_values[0] - 1;
-
}
-
if (ctx->esc_values_i > 1) {
-
ctx->scroll_bottom_margin = ctx->esc_values[1];
-
}
-
if (ctx->scroll_top_margin >= ctx->rows
-
|| ctx->scroll_bottom_margin > ctx->rows
-
|| ctx->scroll_top_margin >= (ctx->scroll_bottom_margin - 1)) {
-
ctx->scroll_top_margin = 0;
-
ctx->scroll_bottom_margin = ctx->rows;
-
}
-
ctx->set_cursor_pos(ctx, 0, 0);
-
break;
-
case 'l':
-
case 'h':
-
mode_toggle(ctx, c);
-
break;
-
case ']':
-
linux_private_parse(ctx);
-
break;
-
}
-
-
ctx->scroll_enabled = r;
-
-
cleanup:
-
ctx->control_sequence = false;
-
ctx->escape = false;
-
}
-
-
static void restore_state(struct flanterm_context *ctx) {
-
ctx->bold = ctx->saved_state_bold;
-
ctx->bg_bold = ctx->saved_state_bg_bold;
-
ctx->reverse_video = ctx->saved_state_reverse_video;
-
ctx->current_charset = ctx->saved_state_current_charset;
-
ctx->current_primary = ctx->saved_state_current_primary;
-
ctx->current_bg = ctx->saved_state_current_bg;
-
-
ctx->restore_state(ctx);
-
}
-
-
static void save_state(struct flanterm_context *ctx) {
-
ctx->save_state(ctx);
-
-
ctx->saved_state_bold = ctx->bold;
-
ctx->saved_state_bg_bold = ctx->bg_bold;
-
ctx->saved_state_reverse_video = ctx->reverse_video;
-
ctx->saved_state_current_charset = ctx->current_charset;
-
ctx->saved_state_current_primary = ctx->current_primary;
-
ctx->saved_state_current_bg = ctx->current_bg;
-
}
-
-
static void escape_parse(struct flanterm_context *ctx, uint8_t c) {
-
ctx->escape_offset++;
-
-
if (ctx->osc == true) {
-
osc_parse(ctx, c);
-
return;
-
}
-
-
if (ctx->control_sequence == true) {
-
control_sequence_parse(ctx, c);
-
return;
-
}
-
-
if (ctx->csi == true) {
-
ctx->csi = false;
-
goto is_csi;
-
}
-
-
size_t x, y;
-
ctx->get_cursor_pos(ctx, &x, &y);
-
-
switch (c) {
-
case ']':
-
ctx->osc_escape = false;
-
ctx->osc = true;
-
return;
-
case '[':
-
is_csi:
-
for (size_t i = 0; i < FLANTERM_MAX_ESC_VALUES; i++)
-
ctx->esc_values[i] = 0;
-
ctx->esc_values_i = 0;
-
ctx->rrr = false;
-
ctx->control_sequence = true;
-
return;
-
case '7':
-
save_state(ctx);
-
break;
-
case '8':
-
restore_state(ctx);
-
break;
-
case 'c':
-
flanterm_context_reinit(ctx);
-
ctx->clear(ctx, true);
-
break;
-
case 'D':
-
if (y == ctx->scroll_bottom_margin - 1) {
-
ctx->scroll(ctx);
-
ctx->set_cursor_pos(ctx, x, y);
-
} else {
-
ctx->set_cursor_pos(ctx, x, y + 1);
-
}
-
break;
-
case 'E':
-
if (y == ctx->scroll_bottom_margin - 1) {
-
ctx->scroll(ctx);
-
ctx->set_cursor_pos(ctx, 0, y);
-
} else {
-
ctx->set_cursor_pos(ctx, 0, y + 1);
-
}
-
break;
-
case 'M':
-
// "Reverse linefeed"
-
if (y == ctx->scroll_top_margin) {
-
ctx->revscroll(ctx);
-
ctx->set_cursor_pos(ctx, 0, y);
-
} else {
-
ctx->set_cursor_pos(ctx, 0, y - 1);
-
}
-
break;
-
case 'Z':
-
if (ctx->callback != NULL) {
-
ctx->callback(ctx, FLANTERM_CB_PRIVATE_ID, 0, 0, 0);
-
}
-
break;
-
case '(':
-
case ')':
-
ctx->g_select = c - '\'';
-
break;
-
}
-
-
ctx->escape = false;
-
}
-
-
static bool dec_special_print(struct flanterm_context *ctx, uint8_t c) {
-
#define FLANTERM_DEC_SPCL_PRN(C) ctx->raw_putchar(ctx, (C)); return true;
-
switch (c) {
-
case '`': FLANTERM_DEC_SPCL_PRN(0x04)
-
case '0': FLANTERM_DEC_SPCL_PRN(0xdb)
-
case '-': FLANTERM_DEC_SPCL_PRN(0x18)
-
case ',': FLANTERM_DEC_SPCL_PRN(0x1b)
-
case '.': FLANTERM_DEC_SPCL_PRN(0x19)
-
case 'a': FLANTERM_DEC_SPCL_PRN(0xb1)
-
case 'f': FLANTERM_DEC_SPCL_PRN(0xf8)
-
case 'g': FLANTERM_DEC_SPCL_PRN(0xf1)
-
case 'h': FLANTERM_DEC_SPCL_PRN(0xb0)
-
case 'j': FLANTERM_DEC_SPCL_PRN(0xd9)
-
case 'k': FLANTERM_DEC_SPCL_PRN(0xbf)
-
case 'l': FLANTERM_DEC_SPCL_PRN(0xda)
-
case 'm': FLANTERM_DEC_SPCL_PRN(0xc0)
-
case 'n': FLANTERM_DEC_SPCL_PRN(0xc5)
-
case 'q': FLANTERM_DEC_SPCL_PRN(0xc4)
-
case 's': FLANTERM_DEC_SPCL_PRN(0x5f)
-
case 't': FLANTERM_DEC_SPCL_PRN(0xc3)
-
case 'u': FLANTERM_DEC_SPCL_PRN(0xb4)
-
case 'v': FLANTERM_DEC_SPCL_PRN(0xc1)
-
case 'w': FLANTERM_DEC_SPCL_PRN(0xc2)
-
case 'x': FLANTERM_DEC_SPCL_PRN(0xb3)
-
case 'y': FLANTERM_DEC_SPCL_PRN(0xf3)
-
case 'z': FLANTERM_DEC_SPCL_PRN(0xf2)
-
case '~': FLANTERM_DEC_SPCL_PRN(0xfa)
-
case '_': FLANTERM_DEC_SPCL_PRN(0xff)
-
case '+': FLANTERM_DEC_SPCL_PRN(0x1a)
-
case '{': FLANTERM_DEC_SPCL_PRN(0xe3)
-
case '}': FLANTERM_DEC_SPCL_PRN(0x9c)
-
}
-
#undef FLANTERM_DEC_SPCL_PRN
-
-
return false;
-
}
-
-
// Following wcwidth related code inherited from:
-
// https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
-
-
struct interval {
-
uint32_t first;
-
uint32_t last;
-
};
-
-
/* auxiliary function for binary search in interval table */
-
static int bisearch(uint32_t ucs, const struct interval *table, int max) {
-
int min = 0;
-
int mid;
-
-
if (ucs < table[0].first || ucs > table[max].last)
-
return 0;
-
while (max >= min) {
-
mid = (min + max) / 2;
-
if (ucs > table[mid].last)
-
min = mid + 1;
-
else if (ucs < table[mid].first)
-
max = mid - 1;
-
else
-
return 1;
-
}
-
-
return 0;
-
}
-
-
int mk_wcwidth(uint32_t ucs) {
-
/* sorted list of non-overlapping intervals of non-spacing characters */
-
/* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
-
static const struct interval combining[] = {
-
{ 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 },
-
{ 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
-
{ 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 },
-
{ 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 },
-
{ 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
-
{ 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
-
{ 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 },
-
{ 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D },
-
{ 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 },
-
{ 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD },
-
{ 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C },
-
{ 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D },
-
{ 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
-
{ 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
-
{ 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
-
{ 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D },
-
{ 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 },
-
{ 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 },
-
{ 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC },
-
{ 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
-
{ 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D },
-
{ 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
-
{ 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
-
{ 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
-
{ 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
-
{ 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
-
{ 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 },
-
{ 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
-
{ 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 },
-
{ 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F },
-
{ 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
-
{ 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
-
{ 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
-
{ 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
-
{ 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
-
{ 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 },
-
{ 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 },
-
{ 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF },
-
{ 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 },
-
{ 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F },
-
{ 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
-
{ 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F },
-
{ 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB },
-
{ 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
-
{ 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
-
{ 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
-
{ 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
-
{ 0xE0100, 0xE01EF }
-
};
-
-
/* test for 8-bit control characters */
-
if (ucs == 0)
-
return 0;
-
if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
-
return 1;
-
-
/* binary search in table of non-spacing characters */
-
if (bisearch(ucs, combining,
-
sizeof(combining) / sizeof(struct interval) - 1))
-
return 0;
-
-
/* if we arrive here, ucs is not a combining or C0/C1 control character */
-
-
return 1 +
-
(ucs >= 0x1100 &&
-
(ucs <= 0x115f || /* Hangul Jamo init. consonants */
-
ucs == 0x2329 || ucs == 0x232a ||
-
(ucs >= 0x2e80 && ucs <= 0xa4cf &&
-
ucs != 0x303f) || /* CJK ... Yi */
-
(ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
-
(ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
-
(ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
-
(ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
-
(ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
-
(ucs >= 0xffe0 && ucs <= 0xffe6) ||
-
(ucs >= 0x20000 && ucs <= 0x2fffd) ||
-
(ucs >= 0x30000 && ucs <= 0x3fffd)));
-
}
-
-
// End of https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c inherited code
-
-
static int unicode_to_cp437(uint64_t code_point) {
-
switch (code_point) {
-
case 0x263a: return 1;
-
case 0x263b: return 2;
-
case 0x2665: return 3;
-
case 0x2666: return 4;
-
case 0x2663: return 5;
-
case 0x2660: return 6;
-
case 0x2022: return 7;
-
case 0x25d8: return 8;
-
case 0x25cb: return 9;
-
case 0x25d9: return 10;
-
case 0x2642: return 11;
-
case 0x2640: return 12;
-
case 0x266a: return 13;
-
case 0x266b: return 14;
-
case 0x263c: return 15;
-
case 0x25ba: return 16;
-
case 0x25c4: return 17;
-
case 0x2195: return 18;
-
case 0x203c: return 19;
-
case 0x00b6: return 20;
-
case 0x00a7: return 21;
-
case 0x25ac: return 22;
-
case 0x21a8: return 23;
-
case 0x2191: return 24;
-
case 0x2193: return 25;
-
case 0x2192: return 26;
-
case 0x2190: return 27;
-
case 0x221f: return 28;
-
case 0x2194: return 29;
-
case 0x25b2: return 30;
-
case 0x25bc: return 31;
-
-
case 0x2302: return 127;
-
case 0x00c7: return 128;
-
case 0x00fc: return 129;
-
case 0x00e9: return 130;
-
case 0x00e2: return 131;
-
case 0x00e4: return 132;
-
case 0x00e0: return 133;
-
case 0x00e5: return 134;
-
case 0x00e7: return 135;
-
case 0x00ea: return 136;
-
case 0x00eb: return 137;
-
case 0x00e8: return 138;
-
case 0x00ef: return 139;
-
case 0x00ee: return 140;
-
case 0x00ec: return 141;
-
case 0x00c4: return 142;
-
case 0x00c5: return 143;
-
case 0x00c9: return 144;
-
case 0x00e6: return 145;
-
case 0x00c6: return 146;
-
case 0x00f4: return 147;
-
case 0x00f6: return 148;
-
case 0x00f2: return 149;
-
case 0x00fb: return 150;
-
case 0x00f9: return 151;
-
case 0x00ff: return 152;
-
case 0x00d6: return 153;
-
case 0x00dc: return 154;
-
case 0x00a2: return 155;
-
case 0x00a3: return 156;
-
case 0x00a5: return 157;
-
case 0x20a7: return 158;
-
case 0x0192: return 159;
-
case 0x00e1: return 160;
-
case 0x00ed: return 161;
-
case 0x00f3: return 162;
-
case 0x00fa: return 163;
-
case 0x00f1: return 164;
-
case 0x00d1: return 165;
-
case 0x00aa: return 166;
-
case 0x00ba: return 167;
-
case 0x00bf: return 168;
-
case 0x2310: return 169;
-
case 0x00ac: return 170;
-
case 0x00bd: return 171;
-
case 0x00bc: return 172;
-
case 0x00a1: return 173;
-
case 0x00ab: return 174;
-
case 0x00bb: return 175;
-
case 0x2591: return 176;
-
case 0x2592: return 177;
-
case 0x2593: return 178;
-
case 0x2502: return 179;
-
case 0x2524: return 180;
-
case 0x2561: return 181;
-
case 0x2562: return 182;
-
case 0x2556: return 183;
-
case 0x2555: return 184;
-
case 0x2563: return 185;
-
case 0x2551: return 186;
-
case 0x2557: return 187;
-
case 0x255d: return 188;
-
case 0x255c: return 189;
-
case 0x255b: return 190;
-
case 0x2510: return 191;
-
case 0x2514: return 192;
-
case 0x2534: return 193;
-
case 0x252c: return 194;
-
case 0x251c: return 195;
-
case 0x2500: return 196;
-
case 0x253c: return 197;
-
case 0x255e: return 198;
-
case 0x255f: return 199;
-
case 0x255a: return 200;
-
case 0x2554: return 201;
-
case 0x2569: return 202;
-
case 0x2566: return 203;
-
case 0x2560: return 204;
-
case 0x2550: return 205;
-
case 0x256c: return 206;
-
case 0x2567: return 207;
-
case 0x2568: return 208;
-
case 0x2564: return 209;
-
case 0x2565: return 210;
-
case 0x2559: return 211;
-
case 0x2558: return 212;
-
case 0x2552: return 213;
-
case 0x2553: return 214;
-
case 0x256b: return 215;
-
case 0x256a: return 216;
-
case 0x2518: return 217;
-
case 0x250c: return 218;
-
case 0x2588: return 219;
-
case 0x2584: return 220;
-
case 0x258c: return 221;
-
case 0x2590: return 222;
-
case 0x2580: return 223;
-
case 0x03b1: return 224;
-
case 0x00df: return 225;
-
case 0x0393: return 226;
-
case 0x03c0: return 227;
-
case 0x03a3: return 228;
-
case 0x03c3: return 229;
-
case 0x00b5: return 230;
-
case 0x03c4: return 231;
-
case 0x03a6: return 232;
-
case 0x0398: return 233;
-
case 0x03a9: return 234;
-
case 0x03b4: return 235;
-
case 0x221e: return 236;
-
case 0x03c6: return 237;
-
case 0x03b5: return 238;
-
case 0x2229: return 239;
-
case 0x2261: return 240;
-
case 0x00b1: return 241;
-
case 0x2265: return 242;
-
case 0x2264: return 243;
-
case 0x2320: return 244;
-
case 0x2321: return 245;
-
case 0x00f7: return 246;
-
case 0x2248: return 247;
-
case 0x00b0: return 248;
-
case 0x2219: return 249;
-
case 0x00b7: return 250;
-
case 0x221a: return 251;
-
case 0x207f: return 252;
-
case 0x00b2: return 253;
-
case 0x25a0: return 254;
-
}
-
-
return -1;
-
}
-
-
static void flanterm_putchar(struct flanterm_context *ctx, uint8_t c) {
-
if (ctx->discard_next || (c == 0x18 || c == 0x1a)) {
-
ctx->discard_next = false;
-
ctx->escape = false;
-
ctx->csi = false;
-
ctx->control_sequence = false;
-
ctx->unicode_remaining = 0;
-
ctx->osc = false;
-
ctx->osc_escape = false;
-
ctx->g_select = 0;
-
return;
-
}
-
-
if (ctx->unicode_remaining != 0) {
-
if ((c & 0xc0) != 0x80) {
-
ctx->unicode_remaining = 0;
-
goto unicode_error;
-
}
-
-
ctx->unicode_remaining--;
-
ctx->code_point |= (uint64_t)(c & 0x3f) << (6 * ctx->unicode_remaining);
-
if (ctx->unicode_remaining != 0) {
-
return;
-
}
-
-
int cc = unicode_to_cp437(ctx->code_point);
-
-
if (cc == -1) {
-
size_t replacement_width = (size_t)mk_wcwidth(ctx->code_point);
-
if (replacement_width > 0) {
-
ctx->raw_putchar(ctx, 0xfe);
-
}
-
for (size_t i = 1; i < replacement_width; i++) {
-
ctx->raw_putchar(ctx, ' ');
-
}
-
} else {
-
ctx->raw_putchar(ctx, cc);
-
}
-
return;
-
}
-
-
unicode_error:
-
if (c >= 0xc0 && c <= 0xf7) {
-
if (c >= 0xc0 && c <= 0xdf) {
-
ctx->unicode_remaining = 1;
-
ctx->code_point = (uint64_t)(c & 0x1f) << 6;
-
} else if (c >= 0xe0 && c <= 0xef) {
-
ctx->unicode_remaining = 2;
-
ctx->code_point = (uint64_t)(c & 0x0f) << (6 * 2);
-
} else if (c >= 0xf0 && c <= 0xf7) {
-
ctx->unicode_remaining = 3;
-
ctx->code_point = (uint64_t)(c & 0x07) << (6 * 3);
-
}
-
return;
-
}
-
-
if (ctx->escape == true) {
-
escape_parse(ctx, c);
-
return;
-
}
-
-
if (ctx->g_select) {
-
ctx->g_select--;
-
switch (c) {
-
case 'B':
-
ctx->charsets[ctx->g_select] = CHARSET_DEFAULT; break;
-
case '0':
-
ctx->charsets[ctx->g_select] = CHARSET_DEC_SPECIAL; break;
-
}
-
ctx->g_select = 0;
-
return;
-
}
-
-
size_t x, y;
-
ctx->get_cursor_pos(ctx, &x, &y);
-
-
switch (c) {
-
case 0x00:
-
case 0x7f:
-
return;
-
case 0x9b:
-
ctx->csi = true;
-
// FALLTHRU
-
case 0x1b:
-
ctx->escape_offset = 0;
-
ctx->escape = true;
-
return;
-
case '\t':
-
if ((x / ctx->tab_size + 1) >= ctx->cols) {
-
ctx->set_cursor_pos(ctx, ctx->cols - 1, y);
-
return;
-
}
-
ctx->set_cursor_pos(ctx, (x / ctx->tab_size + 1) * ctx->tab_size, y);
-
return;
-
case 0x0b:
-
case 0x0c:
-
case '\n':
-
if (y == ctx->scroll_bottom_margin - 1) {
-
ctx->scroll(ctx);
-
ctx->set_cursor_pos(ctx, (ctx->oob_output & FLANTERM_OOB_OUTPUT_ONLCR) ? 0 : x, y);
-
} else {
-
ctx->set_cursor_pos(ctx, (ctx->oob_output & FLANTERM_OOB_OUTPUT_ONLCR) ? 0 : x, y + 1);
-
}
-
return;
-
case '\b':
-
ctx->set_cursor_pos(ctx, x - 1, y);
-
return;
-
case '\r':
-
ctx->set_cursor_pos(ctx, 0, y);
-
return;
-
case '\a':
-
// The bell is handled by the kernel
-
if (ctx->callback != NULL) {
-
ctx->callback(ctx, FLANTERM_CB_BELL, 0, 0, 0);
-
}
-
return;
-
case 14:
-
// Move to G1 set
-
ctx->current_charset = 1;
-
return;
-
case 15:
-
// Move to G0 set
-
ctx->current_charset = 0;
-
return;
-
}
-
-
if (ctx->insert_mode == true) {
-
for (size_t i = ctx->cols - 1; ; i--) {
-
ctx->move_character(ctx, i + 1, y, i, y);
-
if (i == x) {
-
break;
-
}
-
}
-
}
-
-
// Translate character set
-
switch (ctx->charsets[ctx->current_charset]) {
-
case CHARSET_DEFAULT:
-
break;
-
case CHARSET_DEC_SPECIAL:
-
if (dec_special_print(ctx, c)) {
-
return;
-
}
-
break;
-
}
-
-
if (c >= 0x20 && c <= 0x7e) {
-
ctx->raw_putchar(ctx, c);
-
}
-
}
-138
flanterm.h
···
-
/* Copyright (C) 2022-2023 mintsuki and contributors.
-
*
-
* Redistribution and use in source and binary forms, with or without
-
* modification, are permitted provided that the following conditions are met:
-
*
-
* 1. Redistributions of source code must retain the above copyright notice,
-
* this list of conditions and the following disclaimer.
-
*
-
* 2. Redistributions in binary form must reproduce the above copyright notice,
-
* this list of conditions and the following disclaimer in the documentation
-
* and/or other materials provided with the distribution.
-
*
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
-
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-
* POSSIBILITY OF SUCH DAMAGE.
-
*/
-
-
#ifndef _FLANTERM_H
-
#define _FLANTERM_H 1
-
-
#ifdef __cplusplus
-
extern "C" {
-
#endif
-
-
#include <stddef.h>
-
#include <stdint.h>
-
#include <stdbool.h>
-
-
#define FLANTERM_MAX_ESC_VALUES 16
-
-
#define FLANTERM_CB_DEC 10
-
#define FLANTERM_CB_BELL 20
-
#define FLANTERM_CB_PRIVATE_ID 30
-
#define FLANTERM_CB_STATUS_REPORT 40
-
#define FLANTERM_CB_POS_REPORT 50
-
#define FLANTERM_CB_KBD_LEDS 60
-
#define FLANTERM_CB_MODE 70
-
#define FLANTERM_CB_LINUX 80
-
-
#define FLANTERM_OOB_OUTPUT_OCRNL (1 << 0)
-
#define FLANTERM_OOB_OUTPUT_OFDEL (1 << 1)
-
#define FLANTERM_OOB_OUTPUT_OFILL (1 << 2)
-
#define FLANTERM_OOB_OUTPUT_OLCUC (1 << 3)
-
#define FLANTERM_OOB_OUTPUT_ONLCR (1 << 4)
-
#define FLANTERM_OOB_OUTPUT_ONLRET (1 << 5)
-
#define FLANTERM_OOB_OUTPUT_ONOCR (1 << 6)
-
#define FLANTERM_OOB_OUTPUT_OPOST (1 << 7)
-
-
struct flanterm_context {
-
/* internal use */
-
-
size_t tab_size;
-
bool autoflush;
-
bool cursor_enabled;
-
bool scroll_enabled;
-
bool control_sequence;
-
bool csi;
-
bool escape;
-
bool osc;
-
bool osc_escape;
-
bool rrr;
-
bool discard_next;
-
bool bold;
-
bool bg_bold;
-
bool reverse_video;
-
bool dec_private;
-
bool insert_mode;
-
uint64_t code_point;
-
size_t unicode_remaining;
-
uint8_t g_select;
-
uint8_t charsets[2];
-
size_t current_charset;
-
size_t escape_offset;
-
size_t esc_values_i;
-
size_t saved_cursor_x;
-
size_t saved_cursor_y;
-
size_t current_primary;
-
size_t current_bg;
-
size_t scroll_top_margin;
-
size_t scroll_bottom_margin;
-
uint32_t esc_values[FLANTERM_MAX_ESC_VALUES];
-
uint64_t oob_output;
-
bool saved_state_bold;
-
bool saved_state_bg_bold;
-
bool saved_state_reverse_video;
-
size_t saved_state_current_charset;
-
size_t saved_state_current_primary;
-
size_t saved_state_current_bg;
-
-
/* to be set by backend */
-
-
size_t rows, cols;
-
-
void (*raw_putchar)(struct flanterm_context *, uint8_t c);
-
void (*clear)(struct flanterm_context *, bool move);
-
void (*set_cursor_pos)(struct flanterm_context *, size_t x, size_t y);
-
void (*get_cursor_pos)(struct flanterm_context *, size_t *x, size_t *y);
-
void (*set_text_fg)(struct flanterm_context *, size_t fg);
-
void (*set_text_bg)(struct flanterm_context *, size_t bg);
-
void (*set_text_fg_bright)(struct flanterm_context *, size_t fg);
-
void (*set_text_bg_bright)(struct flanterm_context *, size_t bg);
-
void (*set_text_fg_rgb)(struct flanterm_context *, uint32_t fg);
-
void (*set_text_bg_rgb)(struct flanterm_context *, uint32_t bg);
-
void (*set_text_fg_default)(struct flanterm_context *);
-
void (*set_text_bg_default)(struct flanterm_context *);
-
void (*set_text_fg_default_bright)(struct flanterm_context *);
-
void (*set_text_bg_default_bright)(struct flanterm_context *);
-
void (*move_character)(struct flanterm_context *, size_t new_x, size_t new_y, size_t old_x, size_t old_y);
-
void (*scroll)(struct flanterm_context *);
-
void (*revscroll)(struct flanterm_context *);
-
void (*swap_palette)(struct flanterm_context *);
-
void (*save_state)(struct flanterm_context *);
-
void (*restore_state)(struct flanterm_context *);
-
void (*double_buffer_flush)(struct flanterm_context *);
-
void (*full_refresh)(struct flanterm_context *);
-
void (*deinit)(struct flanterm_context *, void (*)(void *, size_t));
-
-
/* to be set by client */
-
-
void (*callback)(struct flanterm_context *, uint64_t, uint64_t, uint64_t, uint64_t);
-
};
-
-
void flanterm_context_reinit(struct flanterm_context *ctx);
-
void flanterm_write(struct flanterm_context *ctx, const char *buf, size_t count);
-
-
#ifdef __cplusplus
-
}
-
#endif
-
-
#endif
+60
src/colors.zig
···
+
const std = @import("std");
+
+
pub const Palette = extern struct {
+
black: u32,
+
red: u32,
+
green: u32,
+
yellow: u32,
+
blue: u32,
+
magenta: u32,
+
cyan: u32,
+
white: u32,
+
};
+
+
/// Used for escape sequences
+
pub const Color = enum(u8) {
+
black = 30,
+
red = 31,
+
green = 32,
+
yellow = 33,
+
blue = 34,
+
magenta = 35,
+
cyan = 36,
+
white = 37,
+
default = 39,
+
bright_black = 90,
+
bright_red = 91,
+
bright_green = 92,
+
bright_yellow = 93,
+
bright_blue = 94,
+
bright_magenta = 95,
+
bright_cyan = 96,
+
bright_white = 97,
+
+
pub fn esc_seq(comptime self: Color) []const u8 {
+
if (self == .default) return "\x1b[0m";
+
return std.fmt.comptimePrint("\x1b[{}m", .{@intFromEnum(self)});
+
}
+
};
+
+
pub var default_colors: Palette = .{
+
.black = 0x000000,
+
.red = 0xff0000,
+
.green = 0x37dd21,
+
.yellow = 0xfee409,
+
.blue = 0x1460d2,
+
.magenta = 0xff005d,
+
.cyan = 0x00bbbb,
+
.white = 0xbbbbbb,
+
};
+
+
pub var default_bold_colors: Palette = .{
+
.black = 0x545454,
+
.red = 0xf40d17,
+
.green = 0x3bcf1d,
+
.yellow = 0xecc809,
+
.blue = 0x5555ff,
+
.magenta = 0xff55ff,
+
.cyan = 0x6ae3f9,
+
.white = 0xffffff,
+
};
+1424
src/flanterm.c
···
+
/* Copyright (C) 2022-2025 mintsuki and contributors.
+
*
+
* Redistribution and use in source and binary forms, with or without
+
* modification, are permitted provided that the following conditions are met:
+
*
+
* 1. Redistributions of source code must retain the above copyright notice,
+
* this list of conditions and the following disclaimer.
+
*
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
+
* this list of conditions and the following disclaimer in the documentation
+
* and/or other materials provided with the distribution.
+
*
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+
* POSSIBILITY OF SUCH DAMAGE.
+
*/
+
+
#ifdef __cplusplus
+
#error "Please do not compile Flanterm as C++ code! Flanterm should be compiled as C99 or newer."
+
#endif
+
+
#ifndef __STDC_VERSION__
+
#error "Flanterm must be compiled as C99 or newer."
+
#endif
+
+
#include <stdint.h>
+
#include <stddef.h>
+
#include <stdbool.h>
+
+
#ifndef FLANTERM_IN_FLANTERM
+
#define FLANTERM_IN_FLANTERM
+
#endif
+
+
#include "flanterm.h"
+
+
// Tries to implement this standard for terminfo
+
// https://man7.org/linux/man-pages/man4/console_codes.4.html
+
+
static const uint32_t col256[] = {
+
0x000000, 0x00005f, 0x000087, 0x0000af, 0x0000d7, 0x0000ff, 0x005f00, 0x005f5f,
+
0x005f87, 0x005faf, 0x005fd7, 0x005fff, 0x008700, 0x00875f, 0x008787, 0x0087af,
+
0x0087d7, 0x0087ff, 0x00af00, 0x00af5f, 0x00af87, 0x00afaf, 0x00afd7, 0x00afff,
+
0x00d700, 0x00d75f, 0x00d787, 0x00d7af, 0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f,
+
0x00ff87, 0x00ffaf, 0x00ffd7, 0x00ffff, 0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af,
+
0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f, 0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff,
+
0x5f8700, 0x5f875f, 0x5f8787, 0x5f87af, 0x5f87d7, 0x5f87ff, 0x5faf00, 0x5faf5f,
+
0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff, 0x5fd700, 0x5fd75f, 0x5fd787, 0x5fd7af,
+
0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f, 0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff,
+
0x870000, 0x87005f, 0x870087, 0x8700af, 0x8700d7, 0x8700ff, 0x875f00, 0x875f5f,
+
0x875f87, 0x875faf, 0x875fd7, 0x875fff, 0x878700, 0x87875f, 0x878787, 0x8787af,
+
0x8787d7, 0x8787ff, 0x87af00, 0x87af5f, 0x87af87, 0x87afaf, 0x87afd7, 0x87afff,
+
0x87d700, 0x87d75f, 0x87d787, 0x87d7af, 0x87d7d7, 0x87d7ff, 0x87ff00, 0x87ff5f,
+
0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff, 0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af,
+
0xaf00d7, 0xaf00ff, 0xaf5f00, 0xaf5f5f, 0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff,
+
0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af, 0xaf87d7, 0xaf87ff, 0xafaf00, 0xafaf5f,
+
0xafaf87, 0xafafaf, 0xafafd7, 0xafafff, 0xafd700, 0xafd75f, 0xafd787, 0xafd7af,
+
0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f, 0xafff87, 0xafffaf, 0xafffd7, 0xafffff,
+
0xd70000, 0xd7005f, 0xd70087, 0xd700af, 0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f,
+
0xd75f87, 0xd75faf, 0xd75fd7, 0xd75fff, 0xd78700, 0xd7875f, 0xd78787, 0xd787af,
+
0xd787d7, 0xd787ff, 0xd7af00, 0xd7af5f, 0xd7af87, 0xd7afaf, 0xd7afd7, 0xd7afff,
+
0xd7d700, 0xd7d75f, 0xd7d787, 0xd7d7af, 0xd7d7d7, 0xd7d7ff, 0xd7ff00, 0xd7ff5f,
+
0xd7ff87, 0xd7ffaf, 0xd7ffd7, 0xd7ffff, 0xff0000, 0xff005f, 0xff0087, 0xff00af,
+
0xff00d7, 0xff00ff, 0xff5f00, 0xff5f5f, 0xff5f87, 0xff5faf, 0xff5fd7, 0xff5fff,
+
0xff8700, 0xff875f, 0xff8787, 0xff87af, 0xff87d7, 0xff87ff, 0xffaf00, 0xffaf5f,
+
0xffaf87, 0xffafaf, 0xffafd7, 0xffafff, 0xffd700, 0xffd75f, 0xffd787, 0xffd7af,
+
0xffd7d7, 0xffd7ff, 0xffff00, 0xffff5f, 0xffff87, 0xffffaf, 0xffffd7, 0xffffff,
+
0x080808, 0x121212, 0x1c1c1c, 0x262626, 0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e,
+
0x585858, 0x626262, 0x6c6c6c, 0x767676, 0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e,
+
0xa8a8a8, 0xb2b2b2, 0xbcbcbc, 0xc6c6c6, 0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee
+
};
+
+
#define CHARSET_DEFAULT 0
+
#define CHARSET_DEC_SPECIAL 1
+
+
void flanterm_context_reinit(struct flanterm_context *ctx) {
+
ctx->tab_size = 8;
+
ctx->autoflush = true;
+
ctx->cursor_enabled = true;
+
ctx->scroll_enabled = true;
+
ctx->control_sequence = false;
+
ctx->escape = false;
+
ctx->osc = false;
+
ctx->osc_escape = false;
+
ctx->rrr = false;
+
ctx->discard_next = false;
+
ctx->bold = false;
+
ctx->bg_bold = false;
+
ctx->reverse_video = false;
+
ctx->dec_private = false;
+
ctx->insert_mode = false;
+
ctx->csi_unhandled = false;
+
ctx->unicode_remaining = 0;
+
ctx->g_select = 0;
+
ctx->charsets[0] = CHARSET_DEFAULT;
+
ctx->charsets[1] = CHARSET_DEC_SPECIAL;
+
ctx->current_charset = 0;
+
ctx->escape_offset = 0;
+
ctx->esc_values_i = 0;
+
ctx->saved_cursor_x = 0;
+
ctx->saved_cursor_y = 0;
+
ctx->current_primary = (size_t)-1;
+
ctx->current_bg = (size_t)-1;
+
ctx->scroll_top_margin = 0;
+
ctx->scroll_bottom_margin = ctx->rows;
+
ctx->oob_output = FLANTERM_OOB_OUTPUT_ONLCR;
+
}
+
+
static void flanterm_putchar(struct flanterm_context *ctx, uint8_t c);
+
+
void flanterm_write(struct flanterm_context *ctx, const char *buf, size_t count) {
+
for (size_t i = 0; i < count; i++) {
+
flanterm_putchar(ctx, buf[i]);
+
}
+
+
if (ctx->autoflush) {
+
ctx->double_buffer_flush(ctx);
+
}
+
}
+
+
static void sgr(struct flanterm_context *ctx) {
+
size_t i = 0;
+
+
if (!ctx->esc_values_i)
+
goto def;
+
+
for (; i < ctx->esc_values_i; i++) {
+
size_t offset;
+
+
if (ctx->esc_values[i] == 0) {
+
def:
+
if (ctx->reverse_video) {
+
ctx->reverse_video = false;
+
ctx->swap_palette(ctx);
+
}
+
ctx->bold = false;
+
ctx->bg_bold = false;
+
ctx->current_primary = (size_t)-1;
+
ctx->current_bg = (size_t)-1;
+
ctx->set_text_bg_default(ctx);
+
ctx->set_text_fg_default(ctx);
+
continue;
+
}
+
+
else if (ctx->esc_values[i] == 1) {
+
ctx->bold = true;
+
if (ctx->current_primary != (size_t)-1) {
+
if (!ctx->reverse_video) {
+
ctx->set_text_fg_bright(ctx, ctx->current_primary);
+
} else {
+
ctx->set_text_bg_bright(ctx, ctx->current_primary);
+
}
+
} else {
+
if (!ctx->reverse_video) {
+
ctx->set_text_fg_default_bright(ctx);
+
} else {
+
ctx->set_text_bg_default_bright(ctx);
+
}
+
}
+
continue;
+
}
+
+
else if (ctx->esc_values[i] == 5) {
+
ctx->bg_bold = true;
+
if (ctx->current_bg != (size_t)-1) {
+
if (!ctx->reverse_video) {
+
ctx->set_text_bg_bright(ctx, ctx->current_bg);
+
} else {
+
ctx->set_text_fg_bright(ctx, ctx->current_bg);
+
}
+
} else {
+
if (!ctx->reverse_video) {
+
ctx->set_text_bg_default_bright(ctx);
+
} else {
+
ctx->set_text_fg_default_bright(ctx);
+
}
+
}
+
continue;
+
}
+
+
else if (ctx->esc_values[i] == 22) {
+
ctx->bold = false;
+
if (ctx->current_primary != (size_t)-1) {
+
if (!ctx->reverse_video) {
+
ctx->set_text_fg(ctx, ctx->current_primary);
+
} else {
+
ctx->set_text_bg(ctx, ctx->current_primary);
+
}
+
} else {
+
if (!ctx->reverse_video) {
+
ctx->set_text_fg_default(ctx);
+
} else {
+
ctx->set_text_bg_default(ctx);
+
}
+
}
+
continue;
+
}
+
+
else if (ctx->esc_values[i] == 25) {
+
ctx->bg_bold = false;
+
if (ctx->current_bg != (size_t)-1) {
+
if (!ctx->reverse_video) {
+
ctx->set_text_bg(ctx, ctx->current_bg);
+
} else {
+
ctx->set_text_fg(ctx, ctx->current_bg);
+
}
+
} else {
+
if (!ctx->reverse_video) {
+
ctx->set_text_bg_default(ctx);
+
} else {
+
ctx->set_text_fg_default(ctx);
+
}
+
}
+
continue;
+
}
+
+
else if (ctx->esc_values[i] >= 30 && ctx->esc_values[i] <= 37) {
+
offset = 30;
+
ctx->current_primary = ctx->esc_values[i] - offset;
+
+
if (ctx->reverse_video) {
+
goto set_bg;
+
}
+
+
set_fg:
+
if ((ctx->bold && !ctx->reverse_video)
+
|| (ctx->bg_bold && ctx->reverse_video)) {
+
ctx->set_text_fg_bright(ctx, ctx->esc_values[i] - offset);
+
} else {
+
ctx->set_text_fg(ctx, ctx->esc_values[i] - offset);
+
}
+
continue;
+
}
+
+
else if (ctx->esc_values[i] >= 40 && ctx->esc_values[i] <= 47) {
+
offset = 40;
+
ctx->current_bg = ctx->esc_values[i] - offset;
+
+
if (ctx->reverse_video) {
+
goto set_fg;
+
}
+
+
set_bg:
+
if ((ctx->bold && ctx->reverse_video)
+
|| (ctx->bg_bold && !ctx->reverse_video)) {
+
ctx->set_text_bg_bright(ctx, ctx->esc_values[i] - offset);
+
} else {
+
ctx->set_text_bg(ctx, ctx->esc_values[i] - offset);
+
}
+
continue;
+
}
+
+
else if (ctx->esc_values[i] >= 90 && ctx->esc_values[i] <= 97) {
+
offset = 90;
+
ctx->current_primary = ctx->esc_values[i] - offset;
+
+
if (ctx->reverse_video) {
+
goto set_bg_bright;
+
}
+
+
set_fg_bright:
+
ctx->set_text_fg_bright(ctx, ctx->esc_values[i] - offset);
+
continue;
+
}
+
+
else if (ctx->esc_values[i] >= 100 && ctx->esc_values[i] <= 107) {
+
offset = 100;
+
ctx->current_bg = ctx->esc_values[i] - offset;
+
+
if (ctx->reverse_video) {
+
goto set_fg_bright;
+
}
+
+
set_bg_bright:
+
ctx->set_text_bg_bright(ctx, ctx->esc_values[i] - offset);
+
continue;
+
}
+
+
else if (ctx->esc_values[i] == 39) {
+
ctx->current_primary = (size_t)-1;
+
+
if (ctx->reverse_video) {
+
ctx->swap_palette(ctx);
+
}
+
+
if (!ctx->bold) {
+
ctx->set_text_fg_default(ctx);
+
} else {
+
ctx->set_text_fg_default_bright(ctx);
+
}
+
+
if (ctx->reverse_video) {
+
ctx->swap_palette(ctx);
+
}
+
+
continue;
+
}
+
+
else if (ctx->esc_values[i] == 49) {
+
ctx->current_bg = (size_t)-1;
+
+
if (ctx->reverse_video) {
+
ctx->swap_palette(ctx);
+
}
+
+
if (!ctx->bg_bold) {
+
ctx->set_text_bg_default(ctx);
+
} else {
+
ctx->set_text_bg_default_bright(ctx);
+
}
+
+
if (ctx->reverse_video) {
+
ctx->swap_palette(ctx);
+
}
+
+
continue;
+
}
+
+
else if (ctx->esc_values[i] == 7) {
+
if (!ctx->reverse_video) {
+
ctx->reverse_video = true;
+
ctx->swap_palette(ctx);
+
}
+
continue;
+
}
+
+
else if (ctx->esc_values[i] == 27) {
+
if (ctx->reverse_video) {
+
ctx->reverse_video = false;
+
ctx->swap_palette(ctx);
+
}
+
continue;
+
}
+
+
// 256/RGB
+
else if (ctx->esc_values[i] == 38 || ctx->esc_values[i] == 48) {
+
bool fg = ctx->esc_values[i] == 38;
+
+
i++;
+
if (i >= ctx->esc_values_i) {
+
break;
+
}
+
+
switch (ctx->esc_values[i]) {
+
case 2: { // RGB
+
if (i + 3 >= ctx->esc_values_i) {
+
goto out;
+
}
+
+
uint32_t rgb_value = 0;
+
+
rgb_value |= ctx->esc_values[i + 1] << 16;
+
rgb_value |= ctx->esc_values[i + 2] << 8;
+
rgb_value |= ctx->esc_values[i + 3];
+
+
i += 3;
+
+
(fg ? ctx->set_text_fg_rgb : ctx->set_text_bg_rgb)(ctx, rgb_value);
+
+
break;
+
}
+
case 5: { // 256 colors
+
if (i + 1 >= ctx->esc_values_i) {
+
goto out;
+
}
+
+
uint32_t col = ctx->esc_values[i + 1];
+
+
i++;
+
+
if (col < 8) {
+
(fg ? ctx->set_text_fg : ctx->set_text_bg)(ctx, col);
+
} else if (col < 16) {
+
(fg ? ctx->set_text_fg_bright : ctx->set_text_bg_bright)(ctx, col - 8);
+
} else if (col < 256) {
+
uint32_t rgb_value = col256[col - 16];
+
(fg ? ctx->set_text_fg_rgb : ctx->set_text_bg_rgb)(ctx, rgb_value);
+
}
+
+
break;
+
}
+
default: continue;
+
}
+
}
+
}
+
+
out:;
+
}
+
+
static void dec_private_parse(struct flanterm_context *ctx, uint8_t c) {
+
ctx->dec_private = false;
+
+
if (ctx->esc_values_i == 0) {
+
return;
+
}
+
+
bool set;
+
+
switch (c) {
+
case 'h':
+
set = true; break;
+
case 'l':
+
set = false; break;
+
default:
+
return;
+
}
+
+
switch (ctx->esc_values[0]) {
+
case 25: {
+
if (set) {
+
ctx->cursor_enabled = true;
+
} else {
+
ctx->cursor_enabled = false;
+
}
+
return;
+
}
+
}
+
+
if (ctx->callback != NULL) {
+
ctx->callback(ctx, FLANTERM_CB_DEC, ctx->esc_values_i, (uintptr_t)ctx->esc_values, c);
+
}
+
}
+
+
static void linux_private_parse(struct flanterm_context *ctx) {
+
if (ctx->esc_values_i == 0) {
+
return;
+
}
+
+
if (ctx->callback != NULL) {
+
ctx->callback(ctx, FLANTERM_CB_LINUX, ctx->esc_values_i, (uintptr_t)ctx->esc_values, 0);
+
}
+
}
+
+
static void mode_toggle(struct flanterm_context *ctx, uint8_t c) {
+
if (ctx->esc_values_i == 0) {
+
return;
+
}
+
+
bool set;
+
+
switch (c) {
+
case 'h':
+
set = true; break;
+
case 'l':
+
set = false; break;
+
default:
+
return;
+
}
+
+
switch (ctx->esc_values[0]) {
+
case 4:
+
ctx->insert_mode = set; return;
+
}
+
+
if (ctx->callback != NULL) {
+
ctx->callback(ctx, FLANTERM_CB_MODE, ctx->esc_values_i, (uintptr_t)ctx->esc_values, c);
+
}
+
}
+
+
static bool osc_parse(struct flanterm_context *ctx, uint8_t c) {
+
// ESC \ terminates an OSC sequence cleanly
+
// but if ESC is followed by non-\, report failure from osc_parse and
+
// try parsing the character as another escape code
+
if (ctx->osc_escape) {
+
if (c == '\\') {
+
ctx->osc = false;
+
ctx->osc_escape = false;
+
ctx->escape = false;
+
return true;
+
} else {
+
ctx->osc_escape = false;
+
ctx->osc = false;
+
// escape stays true here
+
return false;
+
}
+
}
+
switch (c) {
+
case 0x1b:
+
ctx->osc_escape = true;
+
break;
+
// BEL is the other terminator
+
case '\a':
+
ctx->osc_escape = false;
+
ctx->osc = false;
+
ctx->escape = false;
+
break;
+
default:
+
break;
+
}
+
return true;
+
}
+
+
static void control_sequence_parse(struct flanterm_context *ctx, uint8_t c) {
+
if (ctx->escape_offset == 2) {
+
switch (c) {
+
case '[':
+
ctx->discard_next = true;
+
goto cleanup;
+
case '?':
+
ctx->dec_private = true;
+
return;
+
}
+
}
+
+
if (c >= '0' && c <= '9') {
+
if (ctx->esc_values_i == FLANTERM_MAX_ESC_VALUES) {
+
return;
+
}
+
ctx->rrr = true;
+
ctx->esc_values[ctx->esc_values_i] *= 10;
+
ctx->esc_values[ctx->esc_values_i] += c - '0';
+
return;
+
}
+
+
if (ctx->rrr == true) {
+
ctx->esc_values_i++;
+
ctx->rrr = false;
+
if (c == ';')
+
return;
+
} else if (c == ';') {
+
if (ctx->esc_values_i == FLANTERM_MAX_ESC_VALUES) {
+
return;
+
}
+
ctx->esc_values[ctx->esc_values_i] = 0;
+
ctx->esc_values_i++;
+
return;
+
}
+
+
size_t esc_default;
+
switch (c) {
+
case 'J': case 'K': case 'q':
+
esc_default = 0; break;
+
default:
+
esc_default = 1; break;
+
}
+
+
for (size_t i = ctx->esc_values_i; i < FLANTERM_MAX_ESC_VALUES; i++) {
+
ctx->esc_values[i] = esc_default;
+
}
+
+
if (ctx->dec_private == true) {
+
dec_private_parse(ctx, c);
+
goto cleanup;
+
}
+
+
bool r = ctx->scroll_enabled;
+
ctx->scroll_enabled = false;
+
size_t x, y;
+
ctx->get_cursor_pos(ctx, &x, &y);
+
+
// CSI sequences are terminated by a byte in [0x40,0x7E]
+
// so skip all bytes until the terminator byte
+
if (ctx->csi_unhandled) {
+
if (c >= 0x40 && c <= 0x7E) {
+
ctx->csi_unhandled = false;
+
goto cleanup;
+
}
+
return;
+
}
+
+
switch (c) {
+
// Got ESC in the middle of an escape sequence, start a new one
+
case 0x1B:
+
return;
+
case 'F':
+
x = 0;
+
// FALLTHRU
+
case 'A': {
+
if (ctx->esc_values[0] > y)
+
ctx->esc_values[0] = y;
+
size_t orig_y = y;
+
size_t dest_y = y - ctx->esc_values[0];
+
bool will_be_in_scroll_region = false;
+
if ((ctx->scroll_top_margin >= dest_y && ctx->scroll_top_margin <= orig_y)
+
|| (ctx->scroll_bottom_margin >= dest_y && ctx->scroll_bottom_margin <= orig_y)) {
+
will_be_in_scroll_region = true;
+
}
+
if (will_be_in_scroll_region && dest_y < ctx->scroll_top_margin) {
+
dest_y = ctx->scroll_top_margin;
+
}
+
ctx->set_cursor_pos(ctx, x, dest_y);
+
break;
+
}
+
case 'E':
+
x = 0;
+
// FALLTHRU
+
case 'e':
+
case 'B': {
+
if (y + ctx->esc_values[0] > ctx->rows - 1)
+
ctx->esc_values[0] = (ctx->rows - 1) - y;
+
size_t orig_y = y;
+
size_t dest_y = y + ctx->esc_values[0];
+
bool will_be_in_scroll_region = false;
+
if ((ctx->scroll_top_margin >= orig_y && ctx->scroll_top_margin <= dest_y)
+
|| (ctx->scroll_bottom_margin >= orig_y && ctx->scroll_bottom_margin <= dest_y)) {
+
will_be_in_scroll_region = true;
+
}
+
if (will_be_in_scroll_region && dest_y >= ctx->scroll_bottom_margin) {
+
dest_y = ctx->scroll_bottom_margin - 1;
+
}
+
ctx->set_cursor_pos(ctx, x, dest_y);
+
break;
+
}
+
case 'a':
+
case 'C':
+
if (x + ctx->esc_values[0] > ctx->cols - 1)
+
ctx->esc_values[0] = (ctx->cols - 1) - x;
+
ctx->set_cursor_pos(ctx, x + ctx->esc_values[0], y);
+
break;
+
case 'D':
+
if (ctx->esc_values[0] > x)
+
ctx->esc_values[0] = x;
+
ctx->set_cursor_pos(ctx, x - ctx->esc_values[0], y);
+
break;
+
case 'c':
+
if (ctx->callback != NULL) {
+
ctx->callback(ctx, FLANTERM_CB_PRIVATE_ID, 0, 0, 0);
+
}
+
break;
+
case 'd':
+
ctx->esc_values[0] -= 1;
+
if (ctx->esc_values[0] >= ctx->rows)
+
ctx->esc_values[0] = ctx->rows - 1;
+
ctx->set_cursor_pos(ctx, x, ctx->esc_values[0]);
+
break;
+
case 'G':
+
case '`':
+
ctx->esc_values[0] -= 1;
+
if (ctx->esc_values[0] >= ctx->cols)
+
ctx->esc_values[0] = ctx->cols - 1;
+
ctx->set_cursor_pos(ctx, ctx->esc_values[0], y);
+
break;
+
case 'H':
+
case 'f':
+
if (ctx->esc_values[0] != 0) {
+
ctx->esc_values[0]--;
+
}
+
if (ctx->esc_values[1] != 0) {
+
ctx->esc_values[1]--;
+
}
+
if (ctx->esc_values[1] >= ctx->cols)
+
ctx->esc_values[1] = ctx->cols - 1;
+
if (ctx->esc_values[0] >= ctx->rows)
+
ctx->esc_values[0] = ctx->rows - 1;
+
ctx->set_cursor_pos(ctx, ctx->esc_values[1], ctx->esc_values[0]);
+
break;
+
case 'M': {
+
size_t count = ctx->esc_values[0] > ctx->rows ? ctx->rows : ctx->esc_values[0];
+
for (size_t i = 0; i < count; i++) {
+
ctx->scroll(ctx);
+
}
+
break;
+
}
+
case 'L': {
+
size_t old_scroll_top_margin = ctx->scroll_top_margin;
+
ctx->scroll_top_margin = y;
+
size_t count = ctx->esc_values[0] > ctx->rows ? ctx->rows : ctx->esc_values[0];
+
for (size_t i = 0; i < count; i++) {
+
ctx->revscroll(ctx);
+
}
+
ctx->scroll_top_margin = old_scroll_top_margin;
+
break;
+
}
+
case 'n':
+
switch (ctx->esc_values[0]) {
+
case 5:
+
if (ctx->callback != NULL) {
+
ctx->callback(ctx, FLANTERM_CB_STATUS_REPORT, 0, 0, 0);
+
}
+
break;
+
case 6:
+
if (ctx->callback != NULL) {
+
ctx->callback(ctx, FLANTERM_CB_POS_REPORT, x + 1, y + 1, 0);
+
}
+
break;
+
}
+
break;
+
case 'q':
+
if (ctx->callback != NULL) {
+
ctx->callback(ctx, FLANTERM_CB_KBD_LEDS, ctx->esc_values[0], 0, 0);
+
}
+
break;
+
case 'J':
+
switch (ctx->esc_values[0]) {
+
case 0: {
+
size_t rows_remaining = ctx->rows - (y + 1);
+
size_t cols_diff = ctx->cols - (x + 1);
+
size_t to_clear = rows_remaining * ctx->cols + cols_diff + 1;
+
for (size_t i = 0; i < to_clear; i++) {
+
ctx->raw_putchar(ctx, ' ');
+
}
+
ctx->set_cursor_pos(ctx, x, y);
+
break;
+
}
+
case 1: {
+
ctx->set_cursor_pos(ctx, 0, 0);
+
bool b = false;
+
for (size_t yc = 0; yc < ctx->rows; yc++) {
+
for (size_t xc = 0; xc < ctx->cols; xc++) {
+
ctx->raw_putchar(ctx, ' ');
+
if (xc == x && yc == y) {
+
ctx->set_cursor_pos(ctx, x, y);
+
b = true;
+
break;
+
}
+
}
+
if (b == true)
+
break;
+
}
+
break;
+
}
+
case 2:
+
case 3:
+
ctx->clear(ctx, false);
+
break;
+
}
+
break;
+
case '@':
+
for (size_t i = ctx->cols - 1; ; i--) {
+
ctx->move_character(ctx, i + ctx->esc_values[0], y, i, y);
+
ctx->set_cursor_pos(ctx, i, y);
+
ctx->raw_putchar(ctx, ' ');
+
if (i == x) {
+
break;
+
}
+
}
+
ctx->set_cursor_pos(ctx, x, y);
+
break;
+
case 'P':
+
for (size_t i = x + ctx->esc_values[0]; i < ctx->cols; i++)
+
ctx->move_character(ctx, i - ctx->esc_values[0], y, i, y);
+
ctx->set_cursor_pos(ctx, ctx->cols - ctx->esc_values[0], y);
+
// FALLTHRU
+
case 'X': {
+
size_t count = ctx->esc_values[0] > ctx->cols ? ctx->cols : ctx->esc_values[0];
+
for (size_t i = 0; i < count; i++)
+
ctx->raw_putchar(ctx, ' ');
+
ctx->set_cursor_pos(ctx, x, y);
+
break;
+
}
+
case 'm':
+
sgr(ctx);
+
break;
+
case 's':
+
ctx->get_cursor_pos(ctx, &ctx->saved_cursor_x, &ctx->saved_cursor_y);
+
break;
+
case 'u':
+
ctx->set_cursor_pos(ctx, ctx->saved_cursor_x, ctx->saved_cursor_y);
+
break;
+
case 'K':
+
switch (ctx->esc_values[0]) {
+
case 0: {
+
for (size_t i = x; i < ctx->cols; i++)
+
ctx->raw_putchar(ctx, ' ');
+
ctx->set_cursor_pos(ctx, x, y);
+
break;
+
}
+
case 1: {
+
ctx->set_cursor_pos(ctx, 0, y);
+
for (size_t i = 0; i < x; i++)
+
ctx->raw_putchar(ctx, ' ');
+
break;
+
}
+
case 2: {
+
ctx->set_cursor_pos(ctx, 0, y);
+
for (size_t i = 0; i < ctx->cols; i++)
+
ctx->raw_putchar(ctx, ' ');
+
ctx->set_cursor_pos(ctx, x, y);
+
break;
+
}
+
}
+
break;
+
case 'r':
+
if (ctx->esc_values[0] == 0) {
+
ctx->esc_values[0] = 1;
+
}
+
if (ctx->esc_values[1] == 0) {
+
ctx->esc_values[1] = 1;
+
}
+
ctx->scroll_top_margin = 0;
+
ctx->scroll_bottom_margin = ctx->rows;
+
if (ctx->esc_values_i > 0) {
+
ctx->scroll_top_margin = ctx->esc_values[0] - 1;
+
}
+
if (ctx->esc_values_i > 1) {
+
ctx->scroll_bottom_margin = ctx->esc_values[1];
+
}
+
if (ctx->scroll_top_margin >= ctx->rows
+
|| ctx->scroll_bottom_margin > ctx->rows
+
|| ctx->scroll_top_margin >= (ctx->scroll_bottom_margin - 1)) {
+
ctx->scroll_top_margin = 0;
+
ctx->scroll_bottom_margin = ctx->rows;
+
}
+
ctx->set_cursor_pos(ctx, 0, 0);
+
break;
+
case 'l':
+
case 'h':
+
mode_toggle(ctx, c);
+
break;
+
case ']':
+
linux_private_parse(ctx);
+
break;
+
default:
+
ctx->csi_unhandled = true;
+
return;
+
}
+
+
ctx->scroll_enabled = r;
+
+
cleanup:
+
ctx->control_sequence = false;
+
ctx->escape = false;
+
}
+
+
static void restore_state(struct flanterm_context *ctx) {
+
ctx->bold = ctx->saved_state_bold;
+
ctx->bg_bold = ctx->saved_state_bg_bold;
+
ctx->reverse_video = ctx->saved_state_reverse_video;
+
ctx->current_charset = ctx->saved_state_current_charset;
+
ctx->current_primary = ctx->saved_state_current_primary;
+
ctx->current_bg = ctx->saved_state_current_bg;
+
+
ctx->restore_state(ctx);
+
}
+
+
static void save_state(struct flanterm_context *ctx) {
+
ctx->save_state(ctx);
+
+
ctx->saved_state_bold = ctx->bold;
+
ctx->saved_state_bg_bold = ctx->bg_bold;
+
ctx->saved_state_reverse_video = ctx->reverse_video;
+
ctx->saved_state_current_charset = ctx->current_charset;
+
ctx->saved_state_current_primary = ctx->current_primary;
+
ctx->saved_state_current_bg = ctx->current_bg;
+
}
+
+
static void escape_parse(struct flanterm_context *ctx, uint8_t c) {
+
ctx->escape_offset++;
+
+
if (ctx->osc == true) {
+
// ESC \ is one of the two possible terminators of OSC sequences,
+
// so osc_parse consumes ESC.
+
// If it is then followed by \ it cleans correctly,
+
// otherwise it returns false, and it tries parsing it as another escape sequence
+
if (osc_parse(ctx, c)) {
+
return;
+
}
+
}
+
+
if (ctx->control_sequence == true) {
+
control_sequence_parse(ctx, c);
+
return;
+
}
+
+
size_t x, y;
+
ctx->get_cursor_pos(ctx, &x, &y);
+
+
switch (c) {
+
case ']':
+
ctx->osc_escape = false;
+
ctx->osc = true;
+
return;
+
case '[':
+
for (size_t i = 0; i < FLANTERM_MAX_ESC_VALUES; i++)
+
ctx->esc_values[i] = 0;
+
ctx->esc_values_i = 0;
+
ctx->rrr = false;
+
ctx->csi_unhandled = false;
+
ctx->control_sequence = true;
+
return;
+
case '7':
+
save_state(ctx);
+
break;
+
case '8':
+
restore_state(ctx);
+
break;
+
case 'c':
+
flanterm_context_reinit(ctx);
+
ctx->clear(ctx, true);
+
break;
+
case 'D':
+
if (y == ctx->scroll_bottom_margin - 1) {
+
ctx->scroll(ctx);
+
ctx->set_cursor_pos(ctx, x, y);
+
} else {
+
ctx->set_cursor_pos(ctx, x, y + 1);
+
}
+
break;
+
case 'E':
+
if (y == ctx->scroll_bottom_margin - 1) {
+
ctx->scroll(ctx);
+
ctx->set_cursor_pos(ctx, 0, y);
+
} else {
+
ctx->set_cursor_pos(ctx, 0, y + 1);
+
}
+
break;
+
case 'M':
+
// "Reverse linefeed"
+
if (y == ctx->scroll_top_margin) {
+
ctx->revscroll(ctx);
+
ctx->set_cursor_pos(ctx, 0, y);
+
} else {
+
ctx->set_cursor_pos(ctx, 0, y - 1);
+
}
+
break;
+
case 'Z':
+
if (ctx->callback != NULL) {
+
ctx->callback(ctx, FLANTERM_CB_PRIVATE_ID, 0, 0, 0);
+
}
+
break;
+
case '(':
+
case ')':
+
ctx->g_select = c - '\'';
+
break;
+
}
+
+
ctx->escape = false;
+
}
+
+
static bool dec_special_print(struct flanterm_context *ctx, uint8_t c) {
+
#define FLANTERM_DEC_SPCL_PRN(C) ctx->raw_putchar(ctx, (C)); return true;
+
switch (c) {
+
case '`': FLANTERM_DEC_SPCL_PRN(0x04)
+
case '0': FLANTERM_DEC_SPCL_PRN(0xdb)
+
case '-': FLANTERM_DEC_SPCL_PRN(0x18)
+
case ',': FLANTERM_DEC_SPCL_PRN(0x1b)
+
case '.': FLANTERM_DEC_SPCL_PRN(0x19)
+
case 'a': FLANTERM_DEC_SPCL_PRN(0xb1)
+
case 'f': FLANTERM_DEC_SPCL_PRN(0xf8)
+
case 'g': FLANTERM_DEC_SPCL_PRN(0xf1)
+
case 'h': FLANTERM_DEC_SPCL_PRN(0xb0)
+
case 'j': FLANTERM_DEC_SPCL_PRN(0xd9)
+
case 'k': FLANTERM_DEC_SPCL_PRN(0xbf)
+
case 'l': FLANTERM_DEC_SPCL_PRN(0xda)
+
case 'm': FLANTERM_DEC_SPCL_PRN(0xc0)
+
case 'n': FLANTERM_DEC_SPCL_PRN(0xc5)
+
case 'q': FLANTERM_DEC_SPCL_PRN(0xc4)
+
case 's': FLANTERM_DEC_SPCL_PRN(0x5f)
+
case 't': FLANTERM_DEC_SPCL_PRN(0xc3)
+
case 'u': FLANTERM_DEC_SPCL_PRN(0xb4)
+
case 'v': FLANTERM_DEC_SPCL_PRN(0xc1)
+
case 'w': FLANTERM_DEC_SPCL_PRN(0xc2)
+
case 'x': FLANTERM_DEC_SPCL_PRN(0xb3)
+
case 'y': FLANTERM_DEC_SPCL_PRN(0xf3)
+
case 'z': FLANTERM_DEC_SPCL_PRN(0xf2)
+
case '~': FLANTERM_DEC_SPCL_PRN(0xfa)
+
case '_': FLANTERM_DEC_SPCL_PRN(0xff)
+
case '+': FLANTERM_DEC_SPCL_PRN(0x1a)
+
case '{': FLANTERM_DEC_SPCL_PRN(0xe3)
+
case '}': FLANTERM_DEC_SPCL_PRN(0x9c)
+
}
+
#undef FLANTERM_DEC_SPCL_PRN
+
+
return false;
+
}
+
+
// Following wcwidth related code inherited from:
+
// https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+
+
struct interval {
+
uint32_t first;
+
uint32_t last;
+
};
+
+
/* auxiliary function for binary search in interval table */
+
static int bisearch(uint32_t ucs, const struct interval *table, int max) {
+
int min = 0;
+
int mid;
+
+
if (ucs < table[0].first || ucs > table[max].last)
+
return 0;
+
while (max >= min) {
+
mid = (min + max) / 2;
+
if (ucs > table[mid].last)
+
min = mid + 1;
+
else if (ucs < table[mid].first)
+
max = mid - 1;
+
else
+
return 1;
+
}
+
+
return 0;
+
}
+
+
int mk_wcwidth(uint32_t ucs) {
+
/* sorted list of non-overlapping intervals of non-spacing characters */
+
/* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
+
static const struct interval combining[] = {
+
{ 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 },
+
{ 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
+
{ 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 },
+
{ 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 },
+
{ 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
+
{ 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
+
{ 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 },
+
{ 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D },
+
{ 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 },
+
{ 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD },
+
{ 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C },
+
{ 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D },
+
{ 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
+
{ 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
+
{ 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
+
{ 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D },
+
{ 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 },
+
{ 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 },
+
{ 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC },
+
{ 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
+
{ 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D },
+
{ 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
+
{ 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
+
{ 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
+
{ 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
+
{ 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
+
{ 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 },
+
{ 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
+
{ 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 },
+
{ 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F },
+
{ 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
+
{ 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
+
{ 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
+
{ 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
+
{ 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
+
{ 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 },
+
{ 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 },
+
{ 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF },
+
{ 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 },
+
{ 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F },
+
{ 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
+
{ 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F },
+
{ 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB },
+
{ 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
+
{ 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
+
{ 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
+
{ 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
+
{ 0xE0100, 0xE01EF }
+
};
+
+
/* test for 8-bit control characters */
+
if (ucs == 0)
+
return 0;
+
if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
+
return 1;
+
+
/* binary search in table of non-spacing characters */
+
if (bisearch(ucs, combining,
+
sizeof(combining) / sizeof(struct interval) - 1))
+
return 0;
+
+
/* if we arrive here, ucs is not a combining or C0/C1 control character */
+
+
return 1 +
+
(ucs >= 0x1100 &&
+
(ucs <= 0x115f || /* Hangul Jamo init. consonants */
+
ucs == 0x2329 || ucs == 0x232a ||
+
(ucs >= 0x2e80 && ucs <= 0xa4cf &&
+
ucs != 0x303f) || /* CJK ... Yi */
+
(ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
+
(ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
+
(ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
+
(ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
+
(ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
+
(ucs >= 0xffe0 && ucs <= 0xffe6) ||
+
(ucs >= 0x20000 && ucs <= 0x2fffd) ||
+
(ucs >= 0x30000 && ucs <= 0x3fffd)));
+
}
+
+
// End of https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c inherited code
+
+
static int unicode_to_cp437(uint64_t code_point) {
+
switch (code_point) {
+
case 0x263a: return 1;
+
case 0x263b: return 2;
+
case 0x2665: return 3;
+
case 0x2666: return 4;
+
case 0x2663: return 5;
+
case 0x2660: return 6;
+
case 0x2022: return 7;
+
case 0x25d8: return 8;
+
case 0x25cb: return 9;
+
case 0x25d9: return 10;
+
case 0x2642: return 11;
+
case 0x2640: return 12;
+
case 0x266a: return 13;
+
case 0x266b: return 14;
+
case 0x263c: return 15;
+
case 0x25ba: return 16;
+
case 0x25c4: return 17;
+
case 0x2195: return 18;
+
case 0x203c: return 19;
+
case 0x00b6: return 20;
+
case 0x00a7: return 21;
+
case 0x25ac: return 22;
+
case 0x21a8: return 23;
+
case 0x2191: return 24;
+
case 0x2193: return 25;
+
case 0x2192: return 26;
+
case 0x2190: return 27;
+
case 0x221f: return 28;
+
case 0x2194: return 29;
+
case 0x25b2: return 30;
+
case 0x25bc: return 31;
+
+
case 0x2302: return 127;
+
case 0x00c7: return 128;
+
case 0x00fc: return 129;
+
case 0x00e9: return 130;
+
case 0x00e2: return 131;
+
case 0x00e4: return 132;
+
case 0x00e0: return 133;
+
case 0x00e5: return 134;
+
case 0x00e7: return 135;
+
case 0x00ea: return 136;
+
case 0x00eb: return 137;
+
case 0x00e8: return 138;
+
case 0x00ef: return 139;
+
case 0x00ee: return 140;
+
case 0x00ec: return 141;
+
case 0x00c4: return 142;
+
case 0x00c5: return 143;
+
case 0x00c9: return 144;
+
case 0x00e6: return 145;
+
case 0x00c6: return 146;
+
case 0x00f4: return 147;
+
case 0x00f6: return 148;
+
case 0x00f2: return 149;
+
case 0x00fb: return 150;
+
case 0x00f9: return 151;
+
case 0x00ff: return 152;
+
case 0x00d6: return 153;
+
case 0x00dc: return 154;
+
case 0x00a2: return 155;
+
case 0x00a3: return 156;
+
case 0x00a5: return 157;
+
case 0x20a7: return 158;
+
case 0x0192: return 159;
+
case 0x00e1: return 160;
+
case 0x00ed: return 161;
+
case 0x00f3: return 162;
+
case 0x00fa: return 163;
+
case 0x00f1: return 164;
+
case 0x00d1: return 165;
+
case 0x00aa: return 166;
+
case 0x00ba: return 167;
+
case 0x00bf: return 168;
+
case 0x2310: return 169;
+
case 0x00ac: return 170;
+
case 0x00bd: return 171;
+
case 0x00bc: return 172;
+
case 0x00a1: return 173;
+
case 0x00ab: return 174;
+
case 0x00bb: return 175;
+
case 0x2591: return 176;
+
case 0x2592: return 177;
+
case 0x2593: return 178;
+
case 0x2502: return 179;
+
case 0x2524: return 180;
+
case 0x2561: return 181;
+
case 0x2562: return 182;
+
case 0x2556: return 183;
+
case 0x2555: return 184;
+
case 0x2563: return 185;
+
case 0x2551: return 186;
+
case 0x2557: return 187;
+
case 0x255d: return 188;
+
case 0x255c: return 189;
+
case 0x255b: return 190;
+
case 0x2510: return 191;
+
case 0x2514: return 192;
+
case 0x2534: return 193;
+
case 0x252c: return 194;
+
case 0x251c: return 195;
+
case 0x2500: return 196;
+
case 0x253c: return 197;
+
case 0x255e: return 198;
+
case 0x255f: return 199;
+
case 0x255a: return 200;
+
case 0x2554: return 201;
+
case 0x2569: return 202;
+
case 0x2566: return 203;
+
case 0x2560: return 204;
+
case 0x2550: return 205;
+
case 0x256c: return 206;
+
case 0x2567: return 207;
+
case 0x2568: return 208;
+
case 0x2564: return 209;
+
case 0x2565: return 210;
+
case 0x2559: return 211;
+
case 0x2558: return 212;
+
case 0x2552: return 213;
+
case 0x2553: return 214;
+
case 0x256b: return 215;
+
case 0x256a: return 216;
+
case 0x2518: return 217;
+
case 0x250c: return 218;
+
case 0x2588: return 219;
+
case 0x2584: return 220;
+
case 0x258c: return 221;
+
case 0x2590: return 222;
+
case 0x2580: return 223;
+
case 0x03b1: return 224;
+
case 0x00df: return 225;
+
case 0x0393: return 226;
+
case 0x03c0: return 227;
+
case 0x03a3: return 228;
+
case 0x03c3: return 229;
+
case 0x00b5: return 230;
+
case 0x03c4: return 231;
+
case 0x03a6: return 232;
+
case 0x0398: return 233;
+
case 0x03a9: return 234;
+
case 0x03b4: return 235;
+
case 0x221e: return 236;
+
case 0x03c6: return 237;
+
case 0x03b5: return 238;
+
case 0x2229: return 239;
+
case 0x2261: return 240;
+
case 0x00b1: return 241;
+
case 0x2265: return 242;
+
case 0x2264: return 243;
+
case 0x2320: return 244;
+
case 0x2321: return 245;
+
case 0x00f7: return 246;
+
case 0x2248: return 247;
+
case 0x00b0: return 248;
+
case 0x2219: return 249;
+
case 0x00b7: return 250;
+
case 0x221a: return 251;
+
case 0x207f: return 252;
+
case 0x00b2: return 253;
+
case 0x25a0: return 254;
+
}
+
+
return -1;
+
}
+
+
static void flanterm_putchar(struct flanterm_context *ctx, uint8_t c) {
+
if (ctx->discard_next || (c == 0x18 || c == 0x1a)) {
+
ctx->discard_next = false;
+
ctx->escape = false;
+
ctx->control_sequence = false;
+
ctx->unicode_remaining = 0;
+
ctx->osc = false;
+
ctx->osc_escape = false;
+
ctx->g_select = 0;
+
return;
+
}
+
+
if (ctx->unicode_remaining != 0) {
+
if ((c & 0xc0) != 0x80) {
+
ctx->unicode_remaining = 0;
+
goto unicode_error;
+
}
+
+
ctx->unicode_remaining--;
+
ctx->code_point |= (uint64_t)(c & 0x3f) << (6 * ctx->unicode_remaining);
+
if (ctx->unicode_remaining != 0) {
+
return;
+
}
+
+
int cc = unicode_to_cp437(ctx->code_point);
+
+
if (cc == -1) {
+
size_t replacement_width = (size_t)mk_wcwidth(ctx->code_point);
+
if (replacement_width > 0) {
+
ctx->raw_putchar(ctx, 0xfe);
+
}
+
for (size_t i = 1; i < replacement_width; i++) {
+
ctx->raw_putchar(ctx, ' ');
+
}
+
} else {
+
ctx->raw_putchar(ctx, cc);
+
}
+
return;
+
}
+
+
unicode_error:
+
if (c >= 0xc0 && c <= 0xf7) {
+
if (c >= 0xc0 && c <= 0xdf) {
+
ctx->unicode_remaining = 1;
+
ctx->code_point = (uint64_t)(c & 0x1f) << 6;
+
} else if (c >= 0xe0 && c <= 0xef) {
+
ctx->unicode_remaining = 2;
+
ctx->code_point = (uint64_t)(c & 0x0f) << (6 * 2);
+
} else if (c >= 0xf0 && c <= 0xf7) {
+
ctx->unicode_remaining = 3;
+
ctx->code_point = (uint64_t)(c & 0x07) << (6 * 3);
+
}
+
return;
+
}
+
+
if (ctx->escape == true) {
+
escape_parse(ctx, c);
+
return;
+
}
+
+
if (ctx->g_select) {
+
ctx->g_select--;
+
switch (c) {
+
case 'B':
+
ctx->charsets[ctx->g_select] = CHARSET_DEFAULT; break;
+
case '0':
+
ctx->charsets[ctx->g_select] = CHARSET_DEC_SPECIAL; break;
+
}
+
ctx->g_select = 0;
+
return;
+
}
+
+
size_t x, y;
+
ctx->get_cursor_pos(ctx, &x, &y);
+
+
switch (c) {
+
case 0x00:
+
case 0x7f:
+
return;
+
case 0x1b:
+
ctx->escape_offset = 0;
+
ctx->escape = true;
+
return;
+
case '\t':
+
if ((x / ctx->tab_size + 1) >= ctx->cols) {
+
ctx->set_cursor_pos(ctx, ctx->cols - 1, y);
+
return;
+
}
+
ctx->set_cursor_pos(ctx, (x / ctx->tab_size + 1) * ctx->tab_size, y);
+
return;
+
case 0x0b:
+
case 0x0c:
+
case '\n':
+
if (y == ctx->scroll_bottom_margin - 1) {
+
ctx->scroll(ctx);
+
ctx->set_cursor_pos(ctx, (ctx->oob_output & FLANTERM_OOB_OUTPUT_ONLCR) ? 0 : x, y);
+
} else {
+
ctx->set_cursor_pos(ctx, (ctx->oob_output & FLANTERM_OOB_OUTPUT_ONLCR) ? 0 : x, y + 1);
+
}
+
return;
+
case '\b':
+
ctx->set_cursor_pos(ctx, x - 1, y);
+
return;
+
case '\r':
+
ctx->set_cursor_pos(ctx, 0, y);
+
return;
+
case '\a':
+
// The bell is handled by the kernel
+
if (ctx->callback != NULL) {
+
ctx->callback(ctx, FLANTERM_CB_BELL, 0, 0, 0);
+
}
+
return;
+
case 14:
+
// Move to G1 set
+
ctx->current_charset = 1;
+
return;
+
case 15:
+
// Move to G0 set
+
ctx->current_charset = 0;
+
return;
+
}
+
+
if (ctx->insert_mode == true) {
+
for (size_t i = ctx->cols - 1; ; i--) {
+
ctx->move_character(ctx, i + 1, y, i, y);
+
if (i == x) {
+
break;
+
}
+
}
+
}
+
+
// Translate character set
+
switch (ctx->charsets[ctx->current_charset]) {
+
case CHARSET_DEFAULT:
+
break;
+
case CHARSET_DEC_SPECIAL:
+
if (dec_special_print(ctx, c)) {
+
return;
+
}
+
break;
+
}
+
+
if (c >= 0x20 && c <= 0x7e) {
+
ctx->raw_putchar(ctx, c);
+
} else {
+
ctx->raw_putchar(ctx, 0xfe);
+
}
+
}
+
+
void flanterm_flush(struct flanterm_context *ctx) {
+
ctx->double_buffer_flush(ctx);
+
}
+
+
void flanterm_full_refresh(struct flanterm_context *ctx) {
+
ctx->full_refresh(ctx);
+
}
+
+
void flanterm_deinit(struct flanterm_context *ctx, void (*_free)(void *, size_t)) {
+
ctx->deinit(ctx, _free);
+
}
+
+
void flanterm_get_dimensions(struct flanterm_context *ctx, size_t *cols, size_t *rows) {
+
*cols = ctx->cols;
+
*rows = ctx->rows;
+
}
+
+
void flanterm_set_autoflush(struct flanterm_context *ctx, bool state) {
+
ctx->autoflush = state;
+
}
+
+
void flanterm_set_callback(struct flanterm_context *ctx, void (*callback)(struct flanterm_context *, uint64_t, uint64_t, uint64_t, uint64_t)) {
+
ctx->callback = callback;
+
}
+
+
uint64_t flanterm_get_oob_output(struct flanterm_context *ctx) {
+
return ctx->oob_output;
+
}
+
+
void flanterm_set_oob_output(struct flanterm_context *ctx, uint64_t oob_output) {
+
ctx->oob_output = oob_output;
+
}
+80
src/flanterm.h
···
+
/* Copyright (C) 2022-2025 mintsuki and contributors.
+
*
+
* Redistribution and use in source and binary forms, with or without
+
* modification, are permitted provided that the following conditions are met:
+
*
+
* 1. Redistributions of source code must retain the above copyright notice,
+
* this list of conditions and the following disclaimer.
+
*
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
+
* this list of conditions and the following disclaimer in the documentation
+
* and/or other materials provided with the distribution.
+
*
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+
* POSSIBILITY OF SUCH DAMAGE.
+
*/
+
+
#ifndef FLANTERM_H
+
#define FLANTERM_H 1
+
+
#include <stddef.h>
+
#include <stdint.h>
+
#include <stdbool.h>
+
+
#ifdef __cplusplus
+
extern "C" {
+
#endif
+
+
#define FLANTERM_CB_DEC 10
+
#define FLANTERM_CB_BELL 20
+
#define FLANTERM_CB_PRIVATE_ID 30
+
#define FLANTERM_CB_STATUS_REPORT 40
+
#define FLANTERM_CB_POS_REPORT 50
+
#define FLANTERM_CB_KBD_LEDS 60
+
#define FLANTERM_CB_MODE 70
+
#define FLANTERM_CB_LINUX 80
+
+
#define FLANTERM_OOB_OUTPUT_OCRNL (1 << 0)
+
#define FLANTERM_OOB_OUTPUT_OFDEL (1 << 1)
+
#define FLANTERM_OOB_OUTPUT_OFILL (1 << 2)
+
#define FLANTERM_OOB_OUTPUT_OLCUC (1 << 3)
+
#define FLANTERM_OOB_OUTPUT_ONLCR (1 << 4)
+
#define FLANTERM_OOB_OUTPUT_ONLRET (1 << 5)
+
#define FLANTERM_OOB_OUTPUT_ONOCR (1 << 6)
+
#define FLANTERM_OOB_OUTPUT_OPOST (1 << 7)
+
+
#ifdef FLANTERM_IN_FLANTERM
+
+
#include "flanterm_private.h"
+
+
#else
+
+
struct flanterm_context;
+
+
#endif
+
+
void flanterm_write(struct flanterm_context *ctx, const char *buf, size_t count);
+
void flanterm_flush(struct flanterm_context *ctx);
+
void flanterm_full_refresh(struct flanterm_context *ctx);
+
void flanterm_deinit(struct flanterm_context *ctx, void (*_free)(void *ptr, size_t size));
+
+
void flanterm_get_dimensions(struct flanterm_context *ctx, size_t *cols, size_t *rows);
+
void flanterm_set_autoflush(struct flanterm_context *ctx, bool state);
+
void flanterm_set_callback(struct flanterm_context *ctx, void (*callback)(struct flanterm_context *, uint64_t, uint64_t, uint64_t, uint64_t));
+
uint64_t flanterm_get_oob_output(struct flanterm_context *ctx);
+
void flanterm_set_oob_output(struct flanterm_context *ctx, uint64_t oob_output);
+
+
#ifdef __cplusplus
+
}
+
#endif
+
+
#endif
+1254
src/flanterm_backends/fb.c
···
+
/* Copyright (C) 2022-2025 mintsuki and contributors.
+
*
+
* Redistribution and use in source and binary forms, with or without
+
* modification, are permitted provided that the following conditions are met:
+
*
+
* 1. Redistributions of source code must retain the above copyright notice,
+
* this list of conditions and the following disclaimer.
+
*
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
+
* this list of conditions and the following disclaimer in the documentation
+
* and/or other materials provided with the distribution.
+
*
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+
* POSSIBILITY OF SUCH DAMAGE.
+
*/
+
+
#ifdef __cplusplus
+
#error "Please do not compile Flanterm as C++ code! Flanterm should be compiled as C99 or newer."
+
#endif
+
+
#ifndef __STDC_VERSION__
+
#error "Flanterm must be compiled as C99 or newer."
+
#endif
+
+
#if defined(_MSC_VER)
+
#define ALWAYS_INLINE __forceinline
+
#elif defined(__GNUC__) || defined(__clang__)
+
#define ALWAYS_INLINE __attribute__((always_inline)) inline
+
#else
+
#define ALWAYS_INLINE inline
+
#endif
+
+
#include <stdint.h>
+
#include <stddef.h>
+
#include <stdbool.h>
+
+
#ifndef FLANTERM_IN_FLANTERM
+
#define FLANTERM_IN_FLANTERM
+
#endif
+
+
#include "../flanterm.h"
+
#include "fb.h"
+
+
void *memset(void *, int, size_t);
+
void *memcpy(void *, const void *, size_t);
+
+
#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
+
+
#ifndef FLANTERM_FB_BUMP_ALLOC_POOL_SIZE
+
#define FLANTERM_FB_BUMP_ALLOC_POOL_SIZE 873000
+
+
#define FLANTERM_FB_WIDTH_LIMIT 1920
+
#define FLANTERM_FB_HEIGHT_LIMIT 1200
+
#endif
+
+
static uint8_t bump_alloc_pool[FLANTERM_FB_BUMP_ALLOC_POOL_SIZE];
+
static size_t bump_alloc_ptr = 0;
+
+
static void *bump_alloc(size_t s) {
+
static bool base_offset_added = false;
+
if (!base_offset_added) {
+
if ((uintptr_t)bump_alloc_pool & 0xf) {
+
bump_alloc_ptr += 0x10 - ((uintptr_t)bump_alloc_pool & 0xf);
+
}
+
base_offset_added = true;
+
}
+
+
if ((s & 0xf) != 0) {
+
s += 0x10;
+
s &= ~(size_t)0xf;
+
}
+
+
size_t next_ptr = bump_alloc_ptr + s;
+
if (next_ptr > FLANTERM_FB_BUMP_ALLOC_POOL_SIZE) {
+
return NULL;
+
}
+
void *ret = &bump_alloc_pool[bump_alloc_ptr];
+
bump_alloc_ptr = next_ptr;
+
return ret;
+
}
+
+
static bool bump_allocated_instance = false;
+
+
#endif
+
+
// Builtin font originally taken from:
+
// https://github.com/viler-int10h/vga-text-mode-fonts/raw/master/FONTS/PC-OTHER/TOSH-SAT.F16
+
static const uint8_t builtin_font[] = {
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x81, 0x81, 0xa5, 0xa5, 0x81,
+
0x81, 0xa5, 0x99, 0x81, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x7e, 0xff,
+
0xff, 0xdb, 0xdb, 0xff, 0xff, 0xdb, 0xe7, 0xff, 0x7e, 0x3c, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10,
+
0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe,
+
0x7c, 0x7c, 0x38, 0x38, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+
0x3c, 0x3c, 0xdb, 0xff, 0xff, 0xdb, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0xff, 0x66, 0x18, 0x18,
+
0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78,
+
0x78, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+
0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xcc, 0x84, 0x84, 0xcc, 0x78, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd,
+
0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x1e,
+
0x0e, 0x1e, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0xfc, 0x30, 0x30,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x18, 0x1c, 0x1e, 0x16, 0x12,
+
0x10, 0x10, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x38, 0x2c,
+
0x26, 0x32, 0x3a, 0x2e, 0x26, 0x22, 0x62, 0xe2, 0xc6, 0x0e, 0x0c, 0x00,
+
0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf8, 0xfe,
+
0xf8, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+
0x06, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x30, 0x78, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x78,
+
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
+
0xcc, 0xcc, 0x00, 0xcc, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb,
+
0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c,
+
0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78,
+
0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x78, 0x30, 0xfc, 0x00, 0x00,
+
0x00, 0x00, 0x30, 0x78, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+
0x30, 0x30, 0xfc, 0x78, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x18, 0x0c, 0xfe, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0xfe, 0x60, 0x30, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+
0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x24, 0x66, 0xff, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c,
+
0x38, 0x38, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x30, 0x78, 0x78, 0x78, 0x78, 0x30, 0x30, 0x30, 0x00, 0x30,
+
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c,
+
0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+
0x00, 0x18, 0x18, 0x7c, 0xc6, 0xc0, 0xc0, 0x7c, 0x06, 0x06, 0xc6, 0x7c,
+
0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x0c, 0x0c, 0x18, 0x38,
+
0x30, 0x60, 0x60, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
+
0x6c, 0x38, 0x30, 0x76, 0xde, 0xcc, 0xcc, 0xde, 0x76, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x60, 0x60, 0x60,
+
0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30,
+
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x38, 0xfe, 0x38, 0x6c, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
+
0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06,
+
0x0c, 0x0c, 0x18, 0x38, 0x30, 0x60, 0x60, 0xc0, 0xc0, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xc6, 0xc6, 0xc6,
+
0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
+
0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+
0x06, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0x06, 0xc6,
+
0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc,
+
0xfe, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
+
0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x3c, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+
0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18,
+
0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+
0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c,
+
0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+
0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00,
+
0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c,
+
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00,
+
0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x60,
+
0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x00, 0x30,
+
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde,
+
0xde, 0xde, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
+
0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xc6, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+
0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0,
+
0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xcc,
+
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xcc, 0xf8, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
+
0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0,
+
0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+
0xc0, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6,
+
0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30,
+
0x30, 0x30, 0x30, 0x30, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c,
+
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0xc6, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6,
+
0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
+
0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6,
+
0xee, 0xfe, 0xd6, 0xd6, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0xc6, 0xc6, 0xe6, 0xe6, 0xf6, 0xde, 0xce, 0xce, 0xc6, 0xc6,
+
0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+
0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc6,
+
0xc6, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xf6, 0xda,
+
0x6c, 0x06, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc,
+
0xd8, 0xcc, 0xcc, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+
0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+
0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6,
+
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xd6, 0xfe, 0x6c,
+
0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x38,
+
0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc,
+
0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0xfe, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc0, 0xc0,
+
0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60,
+
0x60, 0x60, 0x60, 0x60, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
+
0x60, 0x60, 0x30, 0x38, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+
0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+
0x00, 0x00, 0x18, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x06, 0x06,
+
0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
+
0xc0, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xe6, 0xdc, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc6,
+
0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x76, 0xce, 0xc6,
+
0xc6, 0xc6, 0xc6, 0xce, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30,
+
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xce, 0xc6,
+
0xc6, 0xc6, 0xce, 0x76, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0xc0, 0xc0,
+
0xc0, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x18, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+
0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x1e, 0x06, 0x06,
+
0x06, 0x06, 0x06, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0xc0, 0xc0,
+
0xc0, 0xc6, 0xcc, 0xd8, 0xf0, 0xf0, 0xd8, 0xcc, 0xc6, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+
0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6,
+
0xd6, 0xd6, 0xd6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+
0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0xe6, 0xc6,
+
0xc6, 0xc6, 0xe6, 0xdc, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x76, 0xce, 0xc6, 0xc6, 0xc6, 0xce, 0x76, 0x06, 0x06, 0x06, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0xe6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
+
0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0,
+
0x70, 0x1c, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30,
+
0x30, 0xfe, 0x30, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+
0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
+
0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6,
+
0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
+
0xc6, 0xc6, 0xce, 0x76, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0xfe, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xfe, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x1c, 0x30, 0x30, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x30, 0x30,
+
0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00,
+
0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x30,
+
0x30, 0x30, 0x30, 0x1c, 0x30, 0x30, 0x30, 0x30, 0xe0, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x38, 0x38, 0x6c,
+
0x6c, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
+
0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x18, 0xcc, 0x78, 0x00,
+
0x00, 0x00, 0x6c, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+
0x7c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xc6,
+
0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
+
0x00, 0x7c, 0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x6c, 0x6c, 0x00, 0x7c, 0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xc6,
+
0x7e, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0x06, 0x06,
+
0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38,
+
0x00, 0x7c, 0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc6,
+
0x7c, 0x18, 0x0c, 0x38, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6,
+
0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c,
+
0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00,
+
0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc0, 0xc0, 0xc0,
+
0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x00, 0x38, 0x18, 0x18,
+
0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
+
0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+
0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+
0x3c, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6,
+
0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00,
+
0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+
0x18, 0x30, 0x60, 0x00, 0xfe, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0,
+
0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x36, 0x36,
+
0x76, 0xde, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3c,
+
0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00,
+
0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+
0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6,
+
0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
+
0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+
0x00, 0x10, 0x38, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+
0x7c, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xc6, 0xc6, 0xc6,
+
0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c,
+
0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0x76, 0x06, 0xc6, 0x7c, 0x00,
+
0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+
0x7c, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+
0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
+
0x30, 0x78, 0xcc, 0xc0, 0xc0, 0xcc, 0x78, 0x30, 0x30, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x38, 0x6c, 0x60, 0x60, 0x60, 0xf8, 0x60, 0x60, 0x60, 0xe6,
+
0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0xfc,
+
0x30, 0xfc, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xcc,
+
0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xcc, 0xc6, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18,
+
0x18, 0xd8, 0x70, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0x06, 0x06,
+
0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30,
+
0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+
0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+
0x7c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0xc6, 0xc6, 0xc6,
+
0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
+
0x00, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+
0x76, 0xdc, 0x00, 0xc6, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6,
+
0xc6, 0x00, 0x00, 0x00, 0x00, 0x78, 0xd8, 0xd8, 0x6c, 0x00, 0xfc, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
+
0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xc6,
+
0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0xfe, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0xc0, 0xc2, 0xc6, 0xcc, 0xd8, 0x30, 0x60, 0xdc, 0x86, 0x0c,
+
0x18, 0x3e, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc2, 0xc6, 0xcc, 0xd8, 0x30,
+
0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30,
+
0x00, 0x30, 0x30, 0x30, 0x78, 0x78, 0x78, 0x78, 0x30, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36,
+
0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x88, 0x22, 0x88,
+
0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
+
0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+
0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+
0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18,
+
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18,
+
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18,
+
0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
+
0x36, 0x36, 0x36, 0xf6, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x36, 0x36, 0x36,
+
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xf8, 0x18,
+
0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
+
0x36, 0xf6, 0xf6, 0x06, 0x06, 0xf6, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36,
+
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x06,
+
0x06, 0xf6, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+
0x36, 0xf6, 0xf6, 0x06, 0x06, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0xfe, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18,
+
0x18, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x1f, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff,
+
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x1f, 0x18, 0x18, 0x18,
+
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+
0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+
0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x1f, 0x18, 0x18, 0x1f, 0x1f, 0x18,
+
0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
+
0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+
0x36, 0x37, 0x37, 0x30, 0x30, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x30, 0x30, 0x37, 0x37, 0x36,
+
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0xf7, 0x00,
+
0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0xff, 0xff, 0x00, 0x00, 0xf7, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36,
+
0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, 0x30, 0x30, 0x37, 0x37, 0x36,
+
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
+
0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
+
0x36, 0xf7, 0xf7, 0x00, 0x00, 0xf7, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36,
+
0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff,
+
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x36, 0x36, 0x36,
+
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f,
+
0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+
0x18, 0x1f, 0x1f, 0x18, 0x18, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x18, 0x18, 0x1f, 0x1f, 0x18,
+
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
+
0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+
0x36, 0x36, 0x36, 0xff, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+
0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0xff, 0xff, 0x18,
+
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8,
+
0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x1f, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0,
+
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+
0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x76, 0xd6, 0xdc, 0xc8, 0xc8, 0xdc, 0xd6, 0x76, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
+
0xd8, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0,
+
0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x7e, 0xfe, 0x24, 0x24, 0x24, 0x24, 0x66, 0xc6, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0xfe, 0xfe, 0xc2, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc2, 0xfe,
+
0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xc8, 0xcc,
+
0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x6c, 0x60, 0xc0, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0xfc, 0x98, 0x18, 0x18, 0x18, 0x18,
+
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x30, 0x30, 0x78, 0xcc, 0xcc,
+
0xcc, 0x78, 0x30, 0x30, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
+
0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c,
+
0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xcc, 0x60, 0x30, 0x78, 0xcc,
+
0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x76, 0xbb, 0x99, 0x99, 0xdd, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x02, 0x06, 0x3c, 0x6c, 0xce, 0xd6, 0xd6, 0xe6, 0x6c, 0x78,
+
0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x60, 0xc0, 0xc0, 0xfe,
+
0xc0, 0xc0, 0x60, 0x30, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
+
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0xfc,
+
0x30, 0x30, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
+
0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, 0x36, 0x30, 0x30, 0x30,
+
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x18, 0x18, 0x18,
+
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
+
0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xcc,
+
0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c,
+
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c, 0x00, 0x00,
+
0x00, 0xd8, 0xec, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x0c, 0x18, 0x30, 0x60, 0x7c,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
0x00, 0x00, 0x00, 0x00
+
};
+
+
static ALWAYS_INLINE uint32_t convert_colour(struct flanterm_context *_ctx, uint32_t colour) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
uint32_t r = (colour >> 16) & 0xff;
+
uint32_t g = (colour >> 8) & 0xff;
+
uint32_t b = colour & 0xff;
+
return (r << ctx->red_mask_shift) | (g << ctx->green_mask_shift) | (b << ctx->blue_mask_shift);
+
}
+
+
static void flanterm_fb_save_state(struct flanterm_context *_ctx) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
ctx->saved_state_text_fg = ctx->text_fg;
+
ctx->saved_state_text_bg = ctx->text_bg;
+
ctx->saved_state_cursor_x = ctx->cursor_x;
+
ctx->saved_state_cursor_y = ctx->cursor_y;
+
}
+
+
static void flanterm_fb_restore_state(struct flanterm_context *_ctx) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
ctx->text_fg = ctx->saved_state_text_fg;
+
ctx->text_bg = ctx->saved_state_text_bg;
+
ctx->cursor_x = ctx->saved_state_cursor_x;
+
ctx->cursor_y = ctx->saved_state_cursor_y;
+
}
+
+
static void flanterm_fb_swap_palette(struct flanterm_context *_ctx) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
uint32_t tmp = ctx->text_bg;
+
ctx->text_bg = ctx->text_fg;
+
ctx->text_fg = tmp;
+
}
+
+
static void plot_char_scaled_canvas(struct flanterm_context *_ctx, struct flanterm_fb_char *c, size_t x, size_t y) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
if (x >= _ctx->cols || y >= _ctx->rows) {
+
return;
+
}
+
+
x = ctx->offset_x + x * ctx->glyph_width;
+
y = ctx->offset_y + y * ctx->glyph_height;
+
+
bool *glyph = &ctx->font_bool[c->c * ctx->font_height * ctx->font_width];
+
// naming: fx,fy for font coordinates, gx,gy for glyph coordinates
+
for (size_t gy = 0; gy < ctx->glyph_height; gy++) {
+
uint8_t fy = gy / ctx->font_scale_y;
+
volatile uint32_t *fb_line = ctx->framebuffer + x + (y + gy) * (ctx->pitch / 4);
+
uint32_t *canvas_line = ctx->canvas + x + (y + gy) * ctx->width;
+
bool *glyph_pointer = glyph + (fy * ctx->font_width);
+
for (size_t fx = 0; fx < ctx->font_width; fx++) {
+
for (size_t i = 0; i < ctx->font_scale_x; i++) {
+
size_t gx = ctx->font_scale_x * fx + i;
+
uint32_t bg = c->bg == 0xffffffff ? canvas_line[gx] : c->bg;
+
uint32_t fg = c->fg == 0xffffffff ? canvas_line[gx] : c->fg;
+
fb_line[gx] = *glyph_pointer ? fg : bg;
+
}
+
glyph_pointer++;
+
}
+
}
+
}
+
+
static void plot_char_scaled_uncanvas(struct flanterm_context *_ctx, struct flanterm_fb_char *c, size_t x, size_t y) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
if (x >= _ctx->cols || y >= _ctx->rows) {
+
return;
+
}
+
+
uint32_t default_bg = ctx->default_bg;
+
+
uint32_t bg = c->bg == 0xffffffff ? default_bg : c->bg;
+
uint32_t fg = c->fg == 0xffffffff ? default_bg : c->fg;
+
+
x = ctx->offset_x + x * ctx->glyph_width;
+
y = ctx->offset_y + y * ctx->glyph_height;
+
+
bool *glyph = &ctx->font_bool[c->c * ctx->font_height * ctx->font_width];
+
// naming: fx,fy for font coordinates, gx,gy for glyph coordinates
+
for (size_t gy = 0; gy < ctx->glyph_height; gy++) {
+
uint8_t fy = gy / ctx->font_scale_y;
+
volatile uint32_t *fb_line = ctx->framebuffer + x + (y + gy) * (ctx->pitch / 4);
+
bool *glyph_pointer = glyph + (fy * ctx->font_width);
+
for (size_t fx = 0; fx < ctx->font_width; fx++) {
+
for (size_t i = 0; i < ctx->font_scale_x; i++) {
+
size_t gx = ctx->font_scale_x * fx + i;
+
fb_line[gx] = *glyph_pointer ? fg : bg;
+
}
+
glyph_pointer++;
+
}
+
}
+
}
+
+
static void plot_char_unscaled_canvas(struct flanterm_context *_ctx, struct flanterm_fb_char *c, size_t x, size_t y) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
if (x >= _ctx->cols || y >= _ctx->rows) {
+
return;
+
}
+
+
x = ctx->offset_x + x * ctx->glyph_width;
+
y = ctx->offset_y + y * ctx->glyph_height;
+
+
bool *glyph = &ctx->font_bool[c->c * ctx->font_height * ctx->font_width];
+
// naming: fx,fy for font coordinates, gx,gy for glyph coordinates
+
for (size_t gy = 0; gy < ctx->glyph_height; gy++) {
+
volatile uint32_t *fb_line = ctx->framebuffer + x + (y + gy) * (ctx->pitch / 4);
+
uint32_t *canvas_line = ctx->canvas + x + (y + gy) * ctx->width;
+
bool *glyph_pointer = glyph + (gy * ctx->font_width);
+
for (size_t fx = 0; fx < ctx->font_width; fx++) {
+
uint32_t bg = c->bg == 0xffffffff ? canvas_line[fx] : c->bg;
+
uint32_t fg = c->fg == 0xffffffff ? canvas_line[fx] : c->fg;
+
fb_line[fx] = *(glyph_pointer++) ? fg : bg;
+
}
+
}
+
}
+
+
static void plot_char_unscaled_uncanvas(struct flanterm_context *_ctx, struct flanterm_fb_char *c, size_t x, size_t y) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
if (x >= _ctx->cols || y >= _ctx->rows) {
+
return;
+
}
+
+
uint32_t default_bg = ctx->default_bg;
+
+
uint32_t bg = c->bg == 0xffffffff ? default_bg : c->bg;
+
uint32_t fg = c->fg == 0xffffffff ? default_bg : c->fg;
+
+
x = ctx->offset_x + x * ctx->glyph_width;
+
y = ctx->offset_y + y * ctx->glyph_height;
+
+
bool *glyph = &ctx->font_bool[c->c * ctx->font_height * ctx->font_width];
+
// naming: fx,fy for font coordinates, gx,gy for glyph coordinates
+
for (size_t gy = 0; gy < ctx->glyph_height; gy++) {
+
volatile uint32_t *fb_line = ctx->framebuffer + x + (y + gy) * (ctx->pitch / 4);
+
bool *glyph_pointer = glyph + (gy * ctx->font_width);
+
for (size_t fx = 0; fx < ctx->font_width; fx++) {
+
fb_line[fx] = *(glyph_pointer++) ? fg : bg;
+
}
+
}
+
}
+
+
static inline bool compare_char(struct flanterm_fb_char *a, struct flanterm_fb_char *b) {
+
return !(a->c != b->c || a->bg != b->bg || a->fg != b->fg);
+
}
+
+
static void push_to_queue(struct flanterm_context *_ctx, struct flanterm_fb_char *c, size_t x, size_t y) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
if (x >= _ctx->cols || y >= _ctx->rows) {
+
return;
+
}
+
+
size_t i = y * _ctx->cols + x;
+
+
struct flanterm_fb_queue_item *q = ctx->map[i];
+
+
if (q == NULL) {
+
if (compare_char(&ctx->grid[i], c)) {
+
return;
+
}
+
q = &ctx->queue[ctx->queue_i++];
+
q->x = x;
+
q->y = y;
+
ctx->map[i] = q;
+
}
+
+
q->c = *c;
+
}
+
+
static void flanterm_fb_revscroll(struct flanterm_context *_ctx) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
for (size_t i = (_ctx->scroll_bottom_margin - 1) * _ctx->cols - 1;
+
i >= _ctx->scroll_top_margin * _ctx->cols; i--) {
+
if (i == (size_t)-1) {
+
break;
+
}
+
struct flanterm_fb_char *c;
+
struct flanterm_fb_queue_item *q = ctx->map[i];
+
if (q != NULL) {
+
c = &q->c;
+
} else {
+
c = &ctx->grid[i];
+
}
+
push_to_queue(_ctx, c, (i + _ctx->cols) % _ctx->cols, (i + _ctx->cols) / _ctx->cols);
+
}
+
+
// Clear the first line of the screen.
+
struct flanterm_fb_char empty;
+
empty.c = ' ';
+
empty.fg = ctx->text_fg;
+
empty.bg = ctx->text_bg;
+
for (size_t i = 0; i < _ctx->cols; i++) {
+
push_to_queue(_ctx, &empty, i, _ctx->scroll_top_margin);
+
}
+
}
+
+
static void flanterm_fb_scroll(struct flanterm_context *_ctx) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
for (size_t i = (_ctx->scroll_top_margin + 1) * _ctx->cols;
+
i < _ctx->scroll_bottom_margin * _ctx->cols; i++) {
+
struct flanterm_fb_char *c;
+
struct flanterm_fb_queue_item *q = ctx->map[i];
+
if (q != NULL) {
+
c = &q->c;
+
} else {
+
c = &ctx->grid[i];
+
}
+
push_to_queue(_ctx, c, (i - _ctx->cols) % _ctx->cols, (i - _ctx->cols) / _ctx->cols);
+
}
+
+
// Clear the last line of the screen.
+
struct flanterm_fb_char empty;
+
empty.c = ' ';
+
empty.fg = ctx->text_fg;
+
empty.bg = ctx->text_bg;
+
for (size_t i = 0; i < _ctx->cols; i++) {
+
push_to_queue(_ctx, &empty, i, _ctx->scroll_bottom_margin - 1);
+
}
+
}
+
+
static void flanterm_fb_clear(struct flanterm_context *_ctx, bool move) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
struct flanterm_fb_char empty;
+
empty.c = ' ';
+
empty.fg = ctx->text_fg;
+
empty.bg = ctx->text_bg;
+
for (size_t i = 0; i < _ctx->rows * _ctx->cols; i++) {
+
push_to_queue(_ctx, &empty, i % _ctx->cols, i / _ctx->cols);
+
}
+
+
if (move) {
+
ctx->cursor_x = 0;
+
ctx->cursor_y = 0;
+
}
+
}
+
+
static void flanterm_fb_set_cursor_pos(struct flanterm_context *_ctx, size_t x, size_t y) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
if (x >= _ctx->cols) {
+
if ((int)x < 0) {
+
x = 0;
+
} else {
+
x = _ctx->cols - 1;
+
}
+
}
+
if (y >= _ctx->rows) {
+
if ((int)y < 0) {
+
y = 0;
+
} else {
+
y = _ctx->rows - 1;
+
}
+
}
+
ctx->cursor_x = x;
+
ctx->cursor_y = y;
+
}
+
+
static void flanterm_fb_get_cursor_pos(struct flanterm_context *_ctx, size_t *x, size_t *y) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
*x = ctx->cursor_x >= _ctx->cols ? _ctx->cols - 1 : ctx->cursor_x;
+
*y = ctx->cursor_y >= _ctx->rows ? _ctx->rows - 1 : ctx->cursor_y;
+
}
+
+
static void flanterm_fb_move_character(struct flanterm_context *_ctx, size_t new_x, size_t new_y, size_t old_x, size_t old_y) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
if (old_x >= _ctx->cols || old_y >= _ctx->rows
+
|| new_x >= _ctx->cols || new_y >= _ctx->rows) {
+
return;
+
}
+
+
size_t i = old_x + old_y * _ctx->cols;
+
+
struct flanterm_fb_char *c;
+
struct flanterm_fb_queue_item *q = ctx->map[i];
+
if (q != NULL) {
+
c = &q->c;
+
} else {
+
c = &ctx->grid[i];
+
}
+
+
push_to_queue(_ctx, c, new_x, new_y);
+
}
+
+
static void flanterm_fb_set_text_fg(struct flanterm_context *_ctx, size_t fg) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
ctx->text_fg = ctx->ansi_colours[fg];
+
}
+
+
static void flanterm_fb_set_text_bg(struct flanterm_context *_ctx, size_t bg) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
ctx->text_bg = ctx->ansi_colours[bg];
+
}
+
+
static void flanterm_fb_set_text_fg_bright(struct flanterm_context *_ctx, size_t fg) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
ctx->text_fg = ctx->ansi_bright_colours[fg];
+
}
+
+
static void flanterm_fb_set_text_bg_bright(struct flanterm_context *_ctx, size_t bg) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
ctx->text_bg = ctx->ansi_bright_colours[bg];
+
}
+
+
static void flanterm_fb_set_text_fg_rgb(struct flanterm_context *_ctx, uint32_t fg) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
ctx->text_fg = convert_colour(_ctx, fg);
+
}
+
+
static void flanterm_fb_set_text_bg_rgb(struct flanterm_context *_ctx, uint32_t bg) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
ctx->text_bg = convert_colour(_ctx, bg);
+
}
+
+
static void flanterm_fb_set_text_fg_default(struct flanterm_context *_ctx) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
ctx->text_fg = ctx->default_fg;
+
}
+
+
static void flanterm_fb_set_text_bg_default(struct flanterm_context *_ctx) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
ctx->text_bg = 0xffffffff;
+
}
+
+
static void flanterm_fb_set_text_fg_default_bright(struct flanterm_context *_ctx) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
ctx->text_fg = ctx->default_fg_bright;
+
}
+
+
static void flanterm_fb_set_text_bg_default_bright(struct flanterm_context *_ctx) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
ctx->text_bg = ctx->default_bg_bright;
+
}
+
+
static void draw_cursor(struct flanterm_context *_ctx) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
if (ctx->cursor_x >= _ctx->cols || ctx->cursor_y >= _ctx->rows) {
+
return;
+
}
+
+
size_t i = ctx->cursor_x + ctx->cursor_y * _ctx->cols;
+
+
struct flanterm_fb_char c;
+
struct flanterm_fb_queue_item *q = ctx->map[i];
+
if (q != NULL) {
+
c = q->c;
+
} else {
+
c = ctx->grid[i];
+
}
+
uint32_t tmp = c.fg;
+
c.fg = c.bg;
+
c.bg = tmp;
+
ctx->plot_char(_ctx, &c, ctx->cursor_x, ctx->cursor_y);
+
if (q != NULL) {
+
ctx->grid[i] = q->c;
+
ctx->map[i] = NULL;
+
}
+
}
+
+
static void flanterm_fb_double_buffer_flush(struct flanterm_context *_ctx) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
if (_ctx->cursor_enabled) {
+
draw_cursor(_ctx);
+
}
+
+
for (size_t i = 0; i < ctx->queue_i; i++) {
+
struct flanterm_fb_queue_item *q = &ctx->queue[i];
+
size_t offset = q->y * _ctx->cols + q->x;
+
if (ctx->map[offset] == NULL) {
+
continue;
+
}
+
ctx->plot_char(_ctx, &q->c, q->x, q->y);
+
ctx->grid[offset] = q->c;
+
ctx->map[offset] = NULL;
+
}
+
+
if ((ctx->old_cursor_x != ctx->cursor_x || ctx->old_cursor_y != ctx->cursor_y) || _ctx->cursor_enabled == false) {
+
if (ctx->old_cursor_x < _ctx->cols && ctx->old_cursor_y < _ctx->rows) {
+
ctx->plot_char(_ctx, &ctx->grid[ctx->old_cursor_x + ctx->old_cursor_y * _ctx->cols], ctx->old_cursor_x, ctx->old_cursor_y);
+
}
+
}
+
+
ctx->old_cursor_x = ctx->cursor_x;
+
ctx->old_cursor_y = ctx->cursor_y;
+
+
ctx->queue_i = 0;
+
}
+
+
static void flanterm_fb_raw_putchar(struct flanterm_context *_ctx, uint8_t c) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
if (ctx->cursor_x >= _ctx->cols && (ctx->cursor_y < _ctx->scroll_bottom_margin - 1 || _ctx->scroll_enabled)) {
+
ctx->cursor_x = 0;
+
ctx->cursor_y++;
+
if (ctx->cursor_y == _ctx->scroll_bottom_margin) {
+
ctx->cursor_y--;
+
flanterm_fb_scroll(_ctx);
+
}
+
if (ctx->cursor_y >= _ctx->cols) {
+
ctx->cursor_y = _ctx->cols - 1;
+
}
+
}
+
+
struct flanterm_fb_char ch;
+
ch.c = c;
+
ch.fg = ctx->text_fg;
+
ch.bg = ctx->text_bg;
+
push_to_queue(_ctx, &ch, ctx->cursor_x++, ctx->cursor_y);
+
}
+
+
static void flanterm_fb_full_refresh(struct flanterm_context *_ctx) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
uint32_t default_bg = ctx->default_bg;
+
+
for (size_t y = 0; y < ctx->height; y++) {
+
for (size_t x = 0; x < ctx->width; x++) {
+
if (ctx->canvas != NULL) {
+
ctx->framebuffer[y * (ctx->pitch / sizeof(uint32_t)) + x] = ctx->canvas[y * ctx->width + x];
+
} else {
+
ctx->framebuffer[y * (ctx->pitch / sizeof(uint32_t)) + x] = default_bg;
+
}
+
}
+
}
+
+
for (size_t i = 0; i < (size_t)_ctx->rows * _ctx->cols; i++) {
+
size_t x = i % _ctx->cols;
+
size_t y = i / _ctx->cols;
+
+
ctx->plot_char(_ctx, &ctx->grid[i], x, y);
+
}
+
+
if (_ctx->cursor_enabled) {
+
draw_cursor(_ctx);
+
}
+
}
+
+
static void flanterm_fb_deinit(struct flanterm_context *_ctx, void (*_free)(void *, size_t)) {
+
struct flanterm_fb_context *ctx = (void *)_ctx;
+
+
if (_free == NULL) {
+
#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
+
if (bump_allocated_instance == true) {
+
bump_alloc_ptr = 0;
+
bump_allocated_instance = false;
+
}
+
#endif
+
return;
+
}
+
+
_free(ctx->font_bits, ctx->font_bits_size);
+
_free(ctx->font_bool, ctx->font_bool_size);
+
_free(ctx->grid, ctx->grid_size);
+
_free(ctx->queue, ctx->queue_size);
+
_free(ctx->map, ctx->map_size);
+
+
if (ctx->canvas != NULL) {
+
_free(ctx->canvas, ctx->canvas_size);
+
}
+
+
_free(ctx, sizeof(struct flanterm_fb_context));
+
}
+
+
struct flanterm_context *flanterm_fb_init(
+
void *(*_malloc)(size_t),
+
void (*_free)(void *, size_t),
+
uint32_t *framebuffer, size_t width, size_t height, size_t pitch,
+
uint8_t red_mask_size, uint8_t red_mask_shift,
+
uint8_t green_mask_size, uint8_t green_mask_shift,
+
uint8_t blue_mask_size, uint8_t blue_mask_shift,
+
uint32_t *canvas,
+
uint32_t *ansi_colours, uint32_t *ansi_bright_colours,
+
uint32_t *default_bg, uint32_t *default_fg,
+
uint32_t *default_bg_bright, uint32_t *default_fg_bright,
+
void *font, size_t font_width, size_t font_height, size_t font_spacing,
+
size_t font_scale_x, size_t font_scale_y,
+
size_t margin
+
) {
+
if (font_scale_x == 0 || font_scale_y == 0) {
+
font_scale_x = 1;
+
font_scale_y = 1;
+
if (width >= (1920 + 1920 / 3) && height >= (1080 + 1080 / 3)) {
+
font_scale_x = 2;
+
font_scale_y = 2;
+
}
+
if (width >= (3840 + 3840 / 3) && height >= (2160 + 2160 / 3)) {
+
font_scale_x = 4;
+
font_scale_y = 4;
+
}
+
}
+
+
if (red_mask_size < 8 || red_mask_size != green_mask_size || red_mask_size != blue_mask_size) {
+
return NULL;
+
}
+
+
if (_malloc == NULL) {
+
#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
+
if (bump_allocated_instance == true) {
+
return NULL;
+
}
+
_malloc = bump_alloc;
+
// Limit terminal size if needed
+
if (width > FLANTERM_FB_WIDTH_LIMIT || height > FLANTERM_FB_HEIGHT_LIMIT) {
+
size_t width_limit = width > FLANTERM_FB_WIDTH_LIMIT ? FLANTERM_FB_WIDTH_LIMIT : width;
+
size_t height_limit = height > FLANTERM_FB_HEIGHT_LIMIT ? FLANTERM_FB_HEIGHT_LIMIT : height;
+
+
framebuffer = (uint32_t *)((uintptr_t)framebuffer + ((((height / 2) - (height_limit / 2)) * pitch) + (((width / 2) - (width_limit / 2)) * 4)));
+
+
width = width_limit;
+
height = height_limit;
+
}
+
+
// Force disable canvas
+
canvas = NULL;
+
#else
+
return NULL;
+
#endif
+
}
+
+
struct flanterm_fb_context *ctx = NULL;
+
ctx = _malloc(sizeof(struct flanterm_fb_context));
+
if (ctx == NULL) {
+
goto fail;
+
}
+
+
struct flanterm_context *_ctx = (void *)ctx;
+
memset(ctx, 0, sizeof(struct flanterm_fb_context));
+
+
ctx->red_mask_size = red_mask_size;
+
ctx->red_mask_shift = red_mask_shift + (red_mask_size - 8);
+
ctx->green_mask_size = green_mask_size;
+
ctx->green_mask_shift = green_mask_shift + (green_mask_size - 8);
+
ctx->blue_mask_size = blue_mask_size;
+
ctx->blue_mask_shift = blue_mask_shift + (blue_mask_size - 8);
+
+
if (ansi_colours != NULL) {
+
for (size_t i = 0; i < 8; i++) {
+
ctx->ansi_colours[i] = convert_colour(_ctx, ansi_colours[i]);
+
}
+
} else {
+
ctx->ansi_colours[0] = convert_colour(_ctx, 0x00000000); // black
+
ctx->ansi_colours[1] = convert_colour(_ctx, 0x00aa0000); // red
+
ctx->ansi_colours[2] = convert_colour(_ctx, 0x0000aa00); // green
+
ctx->ansi_colours[3] = convert_colour(_ctx, 0x00aa5500); // brown
+
ctx->ansi_colours[4] = convert_colour(_ctx, 0x000000aa); // blue
+
ctx->ansi_colours[5] = convert_colour(_ctx, 0x00aa00aa); // magenta
+
ctx->ansi_colours[6] = convert_colour(_ctx, 0x0000aaaa); // cyan
+
ctx->ansi_colours[7] = convert_colour(_ctx, 0x00aaaaaa); // grey
+
}
+
+
if (ansi_bright_colours != NULL) {
+
for (size_t i = 0; i < 8; i++) {
+
ctx->ansi_bright_colours[i] = convert_colour(_ctx, ansi_bright_colours[i]);
+
}
+
} else {
+
ctx->ansi_bright_colours[0] = convert_colour(_ctx, 0x00555555); // black
+
ctx->ansi_bright_colours[1] = convert_colour(_ctx, 0x00ff5555); // red
+
ctx->ansi_bright_colours[2] = convert_colour(_ctx, 0x0055ff55); // green
+
ctx->ansi_bright_colours[3] = convert_colour(_ctx, 0x00ffff55); // brown
+
ctx->ansi_bright_colours[4] = convert_colour(_ctx, 0x005555ff); // blue
+
ctx->ansi_bright_colours[5] = convert_colour(_ctx, 0x00ff55ff); // magenta
+
ctx->ansi_bright_colours[6] = convert_colour(_ctx, 0x0055ffff); // cyan
+
ctx->ansi_bright_colours[7] = convert_colour(_ctx, 0x00ffffff); // grey
+
}
+
+
if (default_bg != NULL) {
+
ctx->default_bg = convert_colour(_ctx, *default_bg);
+
} else {
+
ctx->default_bg = 0x00000000; // background (black)
+
}
+
+
if (default_fg != NULL) {
+
ctx->default_fg = convert_colour(_ctx, *default_fg);
+
} else {
+
ctx->default_fg = convert_colour(_ctx, 0x00aaaaaa); // foreground (grey)
+
}
+
+
if (default_bg_bright != NULL) {
+
ctx->default_bg_bright = convert_colour(_ctx, *default_bg_bright);
+
} else {
+
ctx->default_bg_bright = convert_colour(_ctx, 0x00555555); // background (black)
+
}
+
+
if (default_fg_bright != NULL) {
+
ctx->default_fg_bright = convert_colour(_ctx, *default_fg_bright);
+
} else {
+
ctx->default_fg_bright = convert_colour(_ctx, 0x00ffffff); // foreground (grey)
+
}
+
+
ctx->text_fg = ctx->default_fg;
+
ctx->text_bg = 0xffffffff;
+
+
ctx->framebuffer = (void *)framebuffer;
+
ctx->width = width;
+
ctx->height = height;
+
ctx->pitch = pitch;
+
+
#define FONT_BYTES ((font_width * font_height * FLANTERM_FB_FONT_GLYPHS) / 8)
+
+
if (font != NULL) {
+
ctx->font_width = font_width;
+
ctx->font_height = font_height;
+
ctx->font_bits_size = FONT_BYTES;
+
ctx->font_bits = _malloc(ctx->font_bits_size);
+
if (ctx->font_bits == NULL) {
+
goto fail;
+
}
+
memcpy(ctx->font_bits, font, ctx->font_bits_size);
+
} else {
+
ctx->font_width = font_width = 8;
+
ctx->font_height = font_height = 16;
+
ctx->font_bits_size = FONT_BYTES;
+
font_spacing = 1;
+
ctx->font_bits = _malloc(ctx->font_bits_size);
+
if (ctx->font_bits == NULL) {
+
goto fail;
+
}
+
memcpy(ctx->font_bits, builtin_font, ctx->font_bits_size);
+
}
+
+
#undef FONT_BYTES
+
+
ctx->font_width += font_spacing;
+
+
ctx->font_bool_size = FLANTERM_FB_FONT_GLYPHS * font_height * ctx->font_width * sizeof(bool);
+
ctx->font_bool = _malloc(ctx->font_bool_size);
+
if (ctx->font_bool == NULL) {
+
goto fail;
+
}
+
+
for (size_t i = 0; i < FLANTERM_FB_FONT_GLYPHS; i++) {
+
uint8_t *glyph = &ctx->font_bits[i * font_height];
+
+
for (size_t y = 0; y < font_height; y++) {
+
// NOTE: the characters in VGA fonts are always one byte wide.
+
// 9 dot wide fonts have 8 dots and one empty column, except
+
// characters 0xC0-0xDF replicate column 9.
+
for (size_t x = 0; x < 8; x++) {
+
size_t offset = i * font_height * ctx->font_width + y * ctx->font_width + x;
+
+
if ((glyph[y] & (0x80 >> x))) {
+
ctx->font_bool[offset] = true;
+
} else {
+
ctx->font_bool[offset] = false;
+
}
+
}
+
// fill columns above 8 like VGA Line Graphics Mode does
+
for (size_t x = 8; x < ctx->font_width; x++) {
+
size_t offset = i * font_height * ctx->font_width + y * ctx->font_width + x;
+
+
if (i >= 0xc0 && i <= 0xdf) {
+
ctx->font_bool[offset] = (glyph[y] & 1);
+
} else {
+
ctx->font_bool[offset] = false;
+
}
+
}
+
}
+
}
+
+
ctx->font_scale_x = font_scale_x;
+
ctx->font_scale_y = font_scale_y;
+
+
ctx->glyph_width = ctx->font_width * font_scale_x;
+
ctx->glyph_height = font_height * font_scale_y;
+
+
_ctx->cols = (ctx->width - margin * 2) / ctx->glyph_width;
+
_ctx->rows = (ctx->height - margin * 2) / ctx->glyph_height;
+
+
ctx->offset_x = margin + ((ctx->width - margin * 2) % ctx->glyph_width) / 2;
+
ctx->offset_y = margin + ((ctx->height - margin * 2) % ctx->glyph_height) / 2;
+
+
ctx->grid_size = _ctx->rows * _ctx->cols * sizeof(struct flanterm_fb_char);
+
ctx->grid = _malloc(ctx->grid_size);
+
if (ctx->grid == NULL) {
+
goto fail;
+
}
+
for (size_t i = 0; i < _ctx->rows * _ctx->cols; i++) {
+
ctx->grid[i].c = ' ';
+
ctx->grid[i].fg = ctx->text_fg;
+
ctx->grid[i].bg = ctx->text_bg;
+
}
+
+
ctx->queue_size = _ctx->rows * _ctx->cols * sizeof(struct flanterm_fb_queue_item);
+
ctx->queue = _malloc(ctx->queue_size);
+
if (ctx->queue == NULL) {
+
goto fail;
+
}
+
ctx->queue_i = 0;
+
memset(ctx->queue, 0, ctx->queue_size);
+
+
ctx->map_size = _ctx->rows * _ctx->cols * sizeof(struct flanterm_fb_queue_item *);
+
ctx->map = _malloc(ctx->map_size);
+
if (ctx->map == NULL) {
+
goto fail;
+
}
+
memset(ctx->map, 0, ctx->map_size);
+
+
if (canvas != NULL) {
+
ctx->canvas_size = ctx->width * ctx->height * sizeof(uint32_t);
+
ctx->canvas = _malloc(ctx->canvas_size);
+
if (ctx->canvas == NULL) {
+
goto fail;
+
}
+
for (size_t i = 0; i < ctx->width * ctx->height; i++) {
+
ctx->canvas[i] = convert_colour(_ctx, canvas[i]);
+
}
+
}
+
+
if (font_scale_x == 1 && font_scale_y == 1) {
+
if (canvas == NULL) {
+
ctx->plot_char = plot_char_unscaled_uncanvas;
+
} else {
+
ctx->plot_char = plot_char_unscaled_canvas;
+
}
+
} else {
+
if (canvas == NULL) {
+
ctx->plot_char = plot_char_scaled_uncanvas;
+
} else {
+
ctx->plot_char = plot_char_scaled_canvas;
+
}
+
}
+
+
_ctx->raw_putchar = flanterm_fb_raw_putchar;
+
_ctx->clear = flanterm_fb_clear;
+
_ctx->set_cursor_pos = flanterm_fb_set_cursor_pos;
+
_ctx->get_cursor_pos = flanterm_fb_get_cursor_pos;
+
_ctx->set_text_fg = flanterm_fb_set_text_fg;
+
_ctx->set_text_bg = flanterm_fb_set_text_bg;
+
_ctx->set_text_fg_bright = flanterm_fb_set_text_fg_bright;
+
_ctx->set_text_bg_bright = flanterm_fb_set_text_bg_bright;
+
_ctx->set_text_fg_rgb = flanterm_fb_set_text_fg_rgb;
+
_ctx->set_text_bg_rgb = flanterm_fb_set_text_bg_rgb;
+
_ctx->set_text_fg_default = flanterm_fb_set_text_fg_default;
+
_ctx->set_text_bg_default = flanterm_fb_set_text_bg_default;
+
_ctx->set_text_fg_default_bright = flanterm_fb_set_text_fg_default_bright;
+
_ctx->set_text_bg_default_bright = flanterm_fb_set_text_bg_default_bright;
+
_ctx->move_character = flanterm_fb_move_character;
+
_ctx->scroll = flanterm_fb_scroll;
+
_ctx->revscroll = flanterm_fb_revscroll;
+
_ctx->swap_palette = flanterm_fb_swap_palette;
+
_ctx->save_state = flanterm_fb_save_state;
+
_ctx->restore_state = flanterm_fb_restore_state;
+
_ctx->double_buffer_flush = flanterm_fb_double_buffer_flush;
+
_ctx->full_refresh = flanterm_fb_full_refresh;
+
_ctx->deinit = flanterm_fb_deinit;
+
+
flanterm_context_reinit(_ctx);
+
flanterm_fb_full_refresh(_ctx);
+
+
#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
+
if (_malloc == bump_alloc) {
+
bump_allocated_instance = true;
+
}
+
#endif
+
+
return _ctx;
+
+
fail:
+
if (ctx == NULL) {
+
return NULL;
+
}
+
+
#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
+
if (_malloc == bump_alloc) {
+
bump_alloc_ptr = 0;
+
return NULL;
+
}
+
#endif
+
+
if (_free == NULL) {
+
return NULL;
+
}
+
+
if (ctx->canvas != NULL) {
+
_free(ctx->canvas, ctx->canvas_size);
+
}
+
if (ctx->map != NULL) {
+
_free(ctx->map, ctx->map_size);
+
}
+
if (ctx->queue != NULL) {
+
_free(ctx->queue, ctx->queue_size);
+
}
+
if (ctx->grid != NULL) {
+
_free(ctx->grid, ctx->grid_size);
+
}
+
if (ctx->font_bool != NULL) {
+
_free(ctx->font_bool, ctx->font_bool_size);
+
}
+
if (ctx->font_bits != NULL) {
+
_free(ctx->font_bits, ctx->font_bits_size);
+
}
+
if (ctx != NULL) {
+
_free(ctx, sizeof(struct flanterm_fb_context));
+
}
+
+
return NULL;
+
}
+68
src/flanterm_backends/fb.h
···
+
/* Copyright (C) 2022-2025 mintsuki and contributors.
+
*
+
* Redistribution and use in source and binary forms, with or without
+
* modification, are permitted provided that the following conditions are met:
+
*
+
* 1. Redistributions of source code must retain the above copyright notice,
+
* this list of conditions and the following disclaimer.
+
*
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
+
* this list of conditions and the following disclaimer in the documentation
+
* and/or other materials provided with the distribution.
+
*
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+
* POSSIBILITY OF SUCH DAMAGE.
+
*/
+
+
#ifndef FLANTERM_FB_H
+
#define FLANTERM_FB_H 1
+
+
#include <stdint.h>
+
#include <stddef.h>
+
#include <stdbool.h>
+
+
#ifdef __cplusplus
+
extern "C" {
+
#endif
+
+
#include "../flanterm.h"
+
+
#ifdef FLANTERM_IN_FLANTERM
+
+
#include "fb_private.h"
+
+
#endif
+
+
struct flanterm_context *flanterm_fb_init(
+
/* If _malloc and _free are nulled, use the bump allocated instance (1 use only). */
+
void *(*_malloc)(size_t size),
+
void (*_free)(void *ptr, size_t size),
+
uint32_t *framebuffer, size_t width, size_t height, size_t pitch,
+
uint8_t red_mask_size, uint8_t red_mask_shift,
+
uint8_t green_mask_size, uint8_t green_mask_shift,
+
uint8_t blue_mask_size, uint8_t blue_mask_shift,
+
uint32_t *canvas, /* If nulled, no canvas. */
+
uint32_t *ansi_colours, uint32_t *ansi_bright_colours, /* If nulled, default. */
+
uint32_t *default_bg, uint32_t *default_fg, /* If nulled, default. */
+
uint32_t *default_bg_bright, uint32_t *default_fg_bright, /* If nulled, default. */
+
/* If font is null, use default font and font_width and font_height ignored. */
+
void *font, size_t font_width, size_t font_height, size_t font_spacing,
+
/* If scale_x and scale_y are 0, automatically scale font based on resolution. */
+
size_t font_scale_x, size_t font_scale_y,
+
size_t margin
+
);
+
+
#ifdef __cplusplus
+
}
+
#endif
+
+
#endif
+121
src/flanterm_backends/fb_private.h
···
+
/* Copyright (C) 2022-2025 mintsuki and contributors.
+
*
+
* Redistribution and use in source and binary forms, with or without
+
* modification, are permitted provided that the following conditions are met:
+
*
+
* 1. Redistributions of source code must retain the above copyright notice,
+
* this list of conditions and the following disclaimer.
+
*
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
+
* this list of conditions and the following disclaimer in the documentation
+
* and/or other materials provided with the distribution.
+
*
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+
* POSSIBILITY OF SUCH DAMAGE.
+
*/
+
+
#ifndef FLANTERM_FB_PRIVATE_H
+
#define FLANTERM_FB_PRIVATE_H 1
+
+
#ifndef FLANTERM_IN_FLANTERM
+
#error "Do not use fb_private.h. Use interfaces defined in fb.h only."
+
#endif
+
+
#include <stdint.h>
+
#include <stddef.h>
+
#include <stdbool.h>
+
+
#ifdef __cplusplus
+
extern "C" {
+
#endif
+
+
#define FLANTERM_FB_FONT_GLYPHS 256
+
+
struct flanterm_fb_char {
+
uint32_t c;
+
uint32_t fg;
+
uint32_t bg;
+
};
+
+
struct flanterm_fb_queue_item {
+
size_t x, y;
+
struct flanterm_fb_char c;
+
};
+
+
struct flanterm_fb_context {
+
struct flanterm_context term;
+
+
void (*plot_char)(struct flanterm_context *ctx, struct flanterm_fb_char *c, size_t x, size_t y);
+
+
size_t font_width;
+
size_t font_height;
+
size_t glyph_width;
+
size_t glyph_height;
+
+
size_t font_scale_x;
+
size_t font_scale_y;
+
+
size_t offset_x, offset_y;
+
+
volatile uint32_t *framebuffer;
+
size_t pitch;
+
size_t width;
+
size_t height;
+
size_t bpp;
+
+
uint8_t red_mask_size, red_mask_shift;
+
uint8_t green_mask_size, green_mask_shift;
+
uint8_t blue_mask_size, blue_mask_shift;
+
+
size_t font_bits_size;
+
uint8_t *font_bits;
+
size_t font_bool_size;
+
bool *font_bool;
+
+
uint32_t ansi_colours[8];
+
uint32_t ansi_bright_colours[8];
+
uint32_t default_fg, default_bg;
+
uint32_t default_fg_bright, default_bg_bright;
+
+
size_t canvas_size;
+
uint32_t *canvas;
+
+
size_t grid_size;
+
size_t queue_size;
+
size_t map_size;
+
+
struct flanterm_fb_char *grid;
+
+
struct flanterm_fb_queue_item *queue;
+
size_t queue_i;
+
+
struct flanterm_fb_queue_item **map;
+
+
uint32_t text_fg;
+
uint32_t text_bg;
+
size_t cursor_x;
+
size_t cursor_y;
+
+
uint32_t saved_state_text_fg;
+
uint32_t saved_state_text_bg;
+
size_t saved_state_cursor_x;
+
size_t saved_state_cursor_y;
+
+
size_t old_cursor_x;
+
size_t old_cursor_y;
+
};
+
+
#ifdef __cplusplus
+
}
+
#endif
+
+
#endif
+123
src/flanterm_private.h
···
+
/* Copyright (C) 2022-2025 mintsuki and contributors.
+
*
+
* Redistribution and use in source and binary forms, with or without
+
* modification, are permitted provided that the following conditions are met:
+
*
+
* 1. Redistributions of source code must retain the above copyright notice,
+
* this list of conditions and the following disclaimer.
+
*
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
+
* this list of conditions and the following disclaimer in the documentation
+
* and/or other materials provided with the distribution.
+
*
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+
* POSSIBILITY OF SUCH DAMAGE.
+
*/
+
+
#ifndef FLANTERM_PRIVATE_H
+
#define FLANTERM_PRIVATE_H 1
+
+
#ifndef FLANTERM_IN_FLANTERM
+
#error "Do not use flanterm_private.h. Use interfaces defined in flanterm.h only."
+
#endif
+
+
#include <stddef.h>
+
#include <stdint.h>
+
#include <stdbool.h>
+
+
#ifdef __cplusplus
+
extern "C" {
+
#endif
+
+
#define FLANTERM_MAX_ESC_VALUES 16
+
+
struct flanterm_context {
+
/* internal use */
+
+
size_t tab_size;
+
bool autoflush;
+
bool cursor_enabled;
+
bool scroll_enabled;
+
bool control_sequence;
+
bool escape;
+
bool osc;
+
bool osc_escape;
+
bool rrr;
+
bool discard_next;
+
bool bold;
+
bool bg_bold;
+
bool reverse_video;
+
bool dec_private;
+
bool insert_mode;
+
bool csi_unhandled;
+
uint64_t code_point;
+
size_t unicode_remaining;
+
uint8_t g_select;
+
uint8_t charsets[2];
+
size_t current_charset;
+
size_t escape_offset;
+
size_t esc_values_i;
+
size_t saved_cursor_x;
+
size_t saved_cursor_y;
+
size_t current_primary;
+
size_t current_bg;
+
size_t scroll_top_margin;
+
size_t scroll_bottom_margin;
+
uint32_t esc_values[FLANTERM_MAX_ESC_VALUES];
+
uint64_t oob_output;
+
bool saved_state_bold;
+
bool saved_state_bg_bold;
+
bool saved_state_reverse_video;
+
size_t saved_state_current_charset;
+
size_t saved_state_current_primary;
+
size_t saved_state_current_bg;
+
+
/* to be set by backend */
+
+
size_t rows, cols;
+
+
void (*raw_putchar)(struct flanterm_context *, uint8_t c);
+
void (*clear)(struct flanterm_context *, bool move);
+
void (*set_cursor_pos)(struct flanterm_context *, size_t x, size_t y);
+
void (*get_cursor_pos)(struct flanterm_context *, size_t *x, size_t *y);
+
void (*set_text_fg)(struct flanterm_context *, size_t fg);
+
void (*set_text_bg)(struct flanterm_context *, size_t bg);
+
void (*set_text_fg_bright)(struct flanterm_context *, size_t fg);
+
void (*set_text_bg_bright)(struct flanterm_context *, size_t bg);
+
void (*set_text_fg_rgb)(struct flanterm_context *, uint32_t fg);
+
void (*set_text_bg_rgb)(struct flanterm_context *, uint32_t bg);
+
void (*set_text_fg_default)(struct flanterm_context *);
+
void (*set_text_bg_default)(struct flanterm_context *);
+
void (*set_text_fg_default_bright)(struct flanterm_context *);
+
void (*set_text_bg_default_bright)(struct flanterm_context *);
+
void (*move_character)(struct flanterm_context *, size_t new_x, size_t new_y, size_t old_x, size_t old_y);
+
void (*scroll)(struct flanterm_context *);
+
void (*revscroll)(struct flanterm_context *);
+
void (*swap_palette)(struct flanterm_context *);
+
void (*save_state)(struct flanterm_context *);
+
void (*restore_state)(struct flanterm_context *);
+
void (*double_buffer_flush)(struct flanterm_context *);
+
void (*full_refresh)(struct flanterm_context *);
+
void (*deinit)(struct flanterm_context *, void (*)(void *, size_t));
+
+
/* to be set by client */
+
+
void (*callback)(struct flanterm_context *, uint64_t, uint64_t, uint64_t, uint64_t);
+
};
+
+
void flanterm_context_reinit(struct flanterm_context *ctx);
+
+
#ifdef __cplusplus
+
}
+
#endif
+
+
#endif
+92
src/root.zig
···
+
pub const Colors = @import("colors.zig");
+
const std = @import("std");
+
const c = @cImport({
+
@cInclude("flanterm.h");
+
@cInclude("flanterm_backends/fb.h");
+
});
+
+
pub const Context = struct {
+
backing: ?*c.struct_flanterm_context,
+
+
const Self = @This();
+
+
/// Initialize the context
+
pub fn init(
+
args: struct {
+
// Malloc and Free
+
malloc: ?*const fn (usize) callconv(.c) ?*anyopaque = null,
+
free: ?*const fn (?*anyopaque, usize) callconv(.c) void = null,
+
// Framebuffer Info (required)
+
fb: [*]u32,
+
width: usize,
+
height: usize,
+
pitch: usize,
+
// Framebuffer Color Info
+
red_mask_size: u8,
+
red_mask_shift: u8,
+
green_mask_size: u8,
+
green_mask_shift: u8,
+
blue_mask_size: u8,
+
blue_mask_shift: u8,
+
// Canvas (scratch space)
+
canvas: ?[*]u32 = null,
+
// Color Pointers
+
ansi_colours: *Colors.Palette = &Colors.default_colors,
+
ansi_bright_colours: *Colors.Palette = &Colors.default_bold_colors,
+
// Default Color choices
+
default_bg: *u32 = &Colors.default_colors.black,
+
default_fg: *u32 = &Colors.default_colors.cyan,
+
default_bg_bright: *u32 = &Colors.default_bold_colors.black,
+
default_fg_bright: *u32 = &Colors.default_bold_colors.cyan,
+
// Font Information
+
font: ?*anyopaque = null,
+
font_width: usize = 0,
+
font_height: usize = 0,
+
font_spacing: usize = 1,
+
// Font Scale values
+
font_scale_x: usize = 0,
+
font_scale_y: usize = 0,
+
// Margin
+
margin: usize = 0,
+
},
+
) Self {
+
const ansi_colours: [*]u32 = @ptrCast(args.ansi_colours);
+
const ansi_bright_colours: [*]u32 = @ptrCast(args.ansi_bright_colours);
+
const ctx = c.flanterm_fb_init(
+
args.malloc,
+
args.free,
+
args.fb,
+
args.width,
+
args.height,
+
args.pitch,
+
args.red_mask_size,
+
args.red_mask_shift,
+
args.green_mask_size,
+
args.green_mask_shift,
+
args.blue_mask_size,
+
args.blue_mask_shift,
+
args.canvas,
+
ansi_colours,
+
ansi_bright_colours,
+
args.default_bg,
+
args.default_fg,
+
args.default_bg_bright,
+
args.default_fg_bright,
+
args.font,
+
args.font_width,
+
args.font_height,
+
args.font_spacing,
+
args.font_scale_x,
+
args.font_scale_y,
+
args.margin,
+
);
+
return .{
+
.backing = ctx,
+
};
+
}
+
+
/// Write to the console
+
pub fn write_slice(self: *Self, buf: []u8) void {
+
c.flanterm_write(self.backing, buf.ptr, buf.len);
+
}
+
};