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

Compare changes

Choose any two refs to compare.

+3
.gitignore
···
···
+
*.d
+
*.o
+
.zig-cache
+1 -1
LICENSE
···
-
Copyright (C) 2022-2024 mintsuki and contributors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
···
+
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:
+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:
```c
-
#include <flanterm/flanterm.h>
-
#include <flanterm/backends/fb.h>
-
struct flanterm_context *ft_ctx = flanterm_fb_simple_init(
-
framebuffer_ptr, framebuffer_width, framebuffer_height, framebuffer_pitch
-
);
```
-
Where `framebuffer_{ptr,width,height,pitch}` represent the corresponding info
-
about the framebuffer to use for this given instance.
To then print to the terminal instance, simply use the `flanterm_write()`
function on the given instance. For example:
```c
-
#include <flanterm/flanterm.h>
const char msg[] = "Hello world\n";
···
### Quick usage
To quickly set up and use a framebuffer Flanterm instance, it is possible to
+
use the `flanterm_fb_init()` function as such:
```c
+
#include <flanterm.h>
+
#include <flanterm_backends/fb.h>
+
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` 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.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.
-1166
backends/fb.c
···
-
/* Copyright (C) 2022-2024 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;
-
}
-
}
-
}
-
}
-
-
#ifdef FLANTERM_FB_ENABLE_MASKING
-
static void plot_char_masked(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;
-
}
-
}
-
}
-
}
-
#endif
-
-
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;
-
}
-
#ifdef FLANTERM_FB_ENABLE_MASKING
-
struct flanterm_fb_char *old = &ctx->grid[offset];
-
if (q->c.bg == old->bg && q->c.fg == old->fg) {
-
plot_char_masked(_ctx, old, &q->c, q->x, q->y);
-
} else {
-
plot_char(_ctx, &q->c, q->x, q->y);
-
}
-
#else
-
plot_char(_ctx, &q->c, q->x, q->y);
-
#endif
-
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-2024 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
-
-
#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",
+
},
+
}
-1355
flanterm.c
···
-
/* Copyright (C) 2022-2024 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': {
-
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;
-
}
-
-
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-2024 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);
+
}
+
};