From 822ac453f53ca85ddffe42aae57c45ddd4c6a75a Mon Sep 17 00:00:00 2001 From: Hao Nguyen Date: Sun, 10 May 2026 04:39:17 +0900 Subject: [PATCH 1/5] update embedded-font-editor page --- landing-page/embedded-font-editor/index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/landing-page/embedded-font-editor/index.html b/landing-page/embedded-font-editor/index.html index 809dae7..fe80520 100644 --- a/landing-page/embedded-font-editor/index.html +++ b/landing-page/embedded-font-editor/index.html @@ -4,7 +4,7 @@ Bitmap Font Editor - +
@@ -63,7 +63,7 @@

Export Font

- - + + From af13e062912d70cb9698e939a87a1edbb9d20158 Mon Sep 17 00:00:00 2001 From: Hao Nguyen Date: Sun, 10 May 2026 05:04:00 +0900 Subject: [PATCH 2/5] support unicode char fallback fix ttf utf8 rendering --- Makefile | 2 +- src/font.c | 10 ++++---- src/main.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 78 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index f8381fa..bc395d9 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VERSION ?= 2.1.0 +VERSION ?= 2.2.0-rc1 # compiler and linker CROSS_COMPILE ?= CC = ${CROSS_COMPILE}gcc diff --git a/src/font.c b/src/font.c index 0cb50c8..4c48b2d 100644 --- a/src/font.c +++ b/src/font.c @@ -23,7 +23,7 @@ static const unsigned char embedded_font1[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 4: (Control) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 5: (Control) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 6: (Control) - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 7: (Control) + 0x20, 0x70, 0xf8, 0x70, 0x20, 0x00, // 7: (Control) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8: (Control) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9: (Control) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 10: (Control) @@ -729,15 +729,15 @@ void draw_string_ttf(SDL_Surface *surface, const char *text, int x, int y, SDL_C SDL_Surface *text_surface; if (ttf_font_shade == 2) { // highest quality - text_surface = TTF_RenderText_Shaded(ttf_font, text, fg, bg); + text_surface = TTF_RenderUTF8_Shaded(ttf_font, text, fg, bg); } else if (ttf_font_shade == 1) { // medium quality - text_surface = TTF_RenderText_Blended(ttf_font, text, fg); + text_surface = TTF_RenderUTF8_Blended(ttf_font, text, fg); } else { - text_surface = TTF_RenderText_Solid(ttf_font, text, fg); + text_surface = TTF_RenderUTF8_Solid(ttf_font, text, fg); } if (!text_surface) { - fprintf(stderr, "TTF_RenderText_Shaded %s failed: %s\n", text, TTF_GetError()); + fprintf(stderr, "TTF_RenderUTF8_Shaded %s failed: %s\n", text, TTF_GetError()); return; } diff --git a/src/main.c b/src/main.c index dd555a7..22d5f77 100644 --- a/src/main.c +++ b/src/main.c @@ -479,6 +479,71 @@ void x_clear(int x1, int y1, int x2, int y2) { SDL_FillRect(main_window.surface, &r, SDL_MapRGB(main_window.surface->format, c.r, c.g, c.b)); } +static void utf8_to_ascii_fallback(const char *src, int src_len, char *dst, int dst_size) { + int i = 0, di = 0; + long u; + + while (i < src_len && di + 1 < dst_size) { + int sl = utf8_size((char *)&src[i]); + if (sl <= 0 || i + sl > src_len) { + break; + } + + utf8_decode((char *)&src[i], &u); + + if (u < 0x80) { + dst[di++] = (char)u; + } else { + switch (u) { + case 0x2500: /* ─ */ + case 0x2501: /* ━ */ + case 0x2504: /* ┄ */ + case 0x2505: /* ┅ */ + case 0x2508: /* ┈ */ + case 0x2509: /* ┉ */ + case 0x2550: /* ═ */ + dst[di++] = '-'; + break; + case 0x2502: /* │ */ + case 0x2503: /* ┃ */ + case 0x2506: /* ┆ */ + case 0x2507: /* ┇ */ + case 0x250A: /* ┊ */ + case 0x250B: /* ┋ */ + case 0x2551: /* ║ */ + dst[di++] = '|'; + break; + case 0x250C: /* ┌ */ + case 0x2510: /* ┐ */ + case 0x2514: /* └ */ + case 0x2518: /* ┘ */ + case 0x251C: /* ├ */ + case 0x2524: /* ┤ */ + case 0x252C: /* ┬ */ + case 0x2534: /* ┴ */ + case 0x253C: /* ┼ */ + case 0x2554: /* ╔ */ + case 0x2557: /* ╗ */ + case 0x255A: /* ╚ */ + case 0x255D: /* ╝ */ + case 0x2560: /* ╠ */ + case 0x2563: /* ╣ */ + case 0x2566: /* ╦ */ + case 0x2569: /* ╩ */ + case 0x256C: /* ╬ */ + dst[di++] = '+'; + break; + default: + dst[di++] = 7; + break; + } + } + + i += sl; + } + dst[di] = '\0'; +} + void x_draws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { int winx = borderpx + x * main_window.char_width, winy = borderpx + y * main_window.char_height, width = charlen * main_window.char_width; // TTF_Font *font = drawing_ctx.font; @@ -568,7 +633,13 @@ void x_draws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { draw_string_ttf(main_window.surface, s, winx, winy, *fg, *bg); } else { // Use bitmap rendering - draw_string(main_window.surface, s, winx, ys, SDL_MapRGB(main_window.surface->format, fg->r, fg->g, fg->b), embedded_font_name); + if (bytelen > charlen) { + char ascii_buf[DRAW_BUF_SIZ]; + utf8_to_ascii_fallback(s, bytelen, ascii_buf, sizeof(ascii_buf)); + draw_string(main_window.surface, ascii_buf, winx, ys, SDL_MapRGB(main_window.surface->format, fg->r, fg->g, fg->b), embedded_font_name); + } else { + draw_string(main_window.surface, s, winx, ys, SDL_MapRGB(main_window.surface->format, fg->r, fg->g, fg->b), embedded_font_name); + } } } From 11162eee02c8ed3dce66ee525d3a107da7ade19b Mon Sep 17 00:00:00 2001 From: Hao Nguyen Date: Thu, 14 May 2026 17:58:41 +0900 Subject: [PATCH 3/5] support changing $TERM with -term command line arg --- src/config.h | 4 ++-- src/main.c | 19 ++++++++++++++++++- src/vt100.c | 2 +- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/config.h b/src/config.h index 649c192..c0b1164 100644 --- a/src/config.h +++ b/src/config.h @@ -17,8 +17,8 @@ static int opt_use_embedded_font_for_keyboard = 0; static const Uint32 BUTTON_HELD_DELAY = 150; // milliseconds between button triggers when held -/* TERM value */ -char termname[] = "xterm"; +/* TERM value - defaults to xterm-256color but can be overridden */ +char *termname = NULL; /* Will be set in main() - initialized to default if not overridden */ unsigned int tabspaces = 4; diff --git a/src/main.c b/src/main.c index 22d5f77..0078563 100644 --- a/src/main.c +++ b/src/main.c @@ -29,7 +29,7 @@ #include "keyboard.h" #include "vt100.h" -#define USAGE "Simple Terminal\nusage: simple-terminal [-h] [-scale 2.0] [-font font.ttf] [-fontsize 14] [-fontshade 0|1|2] [-rotate 0|90|180|270] [-o file] [-q] [-r command ...]\n" +#define USAGE "Simple Terminal\nusage: simple-terminal [-h] [-scale 2.0] [-font font.ttf] [-fontsize 14] [-fontshade 0|1|2] [-rotate 0|90|180|270] [-term xterm-256color|xterm|linux|vt100...] [-o file] [-q] [-r command ...]\n" /* Arbitrary sizes */ #define DRAW_BUF_SIZ 20 * 1024 @@ -147,6 +147,7 @@ SDL_Thread *thread = NULL; char **opt_cmd = NULL; int opt_cmd_size = 0; char *opt_io = NULL; +char *opt_term = NULL; /* override TERM environment variable */ static int embedded_font_name = 1; // 1 or 2 static volatile int thread_should_exit = 0; @@ -1282,6 +1283,15 @@ int main(int argc, char *argv[]) { } continue; } + if (strcmp(argv[i], "-term") == 0) { + if (++i < argc) { + opt_term = argv[i]; + } else { + fprintf(stderr, "Missing argument for -term\n"); + die(USAGE); + } + continue; + } if (strcmp(argv[i], "-useEmbeddedFontForKeyboard") == 0) { if (++i < argc) { opt_use_embedded_font_for_keyboard = atoi(argv[i]); @@ -1327,6 +1337,13 @@ int main(int argc, char *argv[]) { int content_h = main_window.surface ? main_window.surface->h : main_window.height; t_new((content_w - borderpx) / main_window.char_width, (content_h - borderpx) / main_window.char_height); } + + if (opt_term != NULL) { + termname = opt_term; + } else { + termname = "linux"; + } + tty_new(); create_tty_thread(); scale_to_size((int)(main_window.width / opt_scale), (int)(main_window.height / opt_scale)); diff --git a/src/vt100.c b/src/vt100.c index 3c861ac..16391b6 100644 --- a/src/vt100.c +++ b/src/vt100.c @@ -20,7 +20,7 @@ extern unsigned int defaultfg; extern unsigned int defaultbg; extern unsigned int tabspaces; extern char default_shell[]; -extern char termname[]; +extern char *termname; extern int scrollback_lines; /* External variables from main.c */ From 88f17125e14614c466448ac9d0bd6ff0422a4628 Mon Sep 17 00:00:00 2001 From: Hao Nguyen Date: Wed, 13 May 2026 05:35:35 +0900 Subject: [PATCH 4/5] fix some csi errors --- src/vt100.c | 75 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 16 deletions(-) diff --git a/src/vt100.c b/src/vt100.c index 16391b6..401e900 100644 --- a/src/vt100.c +++ b/src/vt100.c @@ -36,6 +36,7 @@ STREscape strescseq; int cmdfd; int iofd = -1; static pid_t pid; +static char last_char[UTF_SIZ]; /* Last character for repeat command */ /* UTF-8 functions */ int utf8_decode(char *s, long *u) { @@ -479,14 +480,14 @@ void csi_parse(void) { char *p = csiescseq.buf; csiescseq.narg = 0; - if (*p == '?') csiescseq.priv = 1, p++; + if (*p == '?' || *p == '>' || *p == '!') csiescseq.priv = 1, p++; while (p < csiescseq.buf + csiescseq.len) { while (isdigit(*p)) { csiescseq.arg[csiescseq.narg] *= 10; csiescseq.arg[csiescseq.narg] += *p++ - '0' /*, noarg = 0 */; } - if (*p == ';' && csiescseq.narg + 1 < ESC_ARG_SIZ) { + if (((*p == ';') || (*p == ':')) && csiescseq.narg + 1 < ESC_ARG_SIZ) { csiescseq.narg++, p++; } else { csiescseq.mode = *p; @@ -640,14 +641,19 @@ void t_set_attr(int *attr, int l) { break; case 38: if (i + 2 < l && attr[i + 1] == 5) { + /* 256-color mode: 38;5;N */ i += 2; if (BETWEEN(attr[i], 0, 255)) { term.c.attr.fg = attr[i]; } else { fprintf(stderr, "erresc: bad fgcolor %d\n", attr[i]); } - } else { - fprintf(stderr, "erresc(38): gfx attr %d unknown\n", attr[i]); + } else if (i + 4 < l && attr[i + 1] == 2) { + /* RGB color mode: 38;2;R;G;B - silently use first color component */ + i += 4; + if (BETWEEN(attr[i - 2], 0, 255)) { + term.c.attr.fg = attr[i - 2]; /* Use R component as palette index */ + } } break; case 39: @@ -655,14 +661,19 @@ void t_set_attr(int *attr, int l) { break; case 48: if (i + 2 < l && attr[i + 1] == 5) { + /* 256-color mode: 48;5;N */ i += 2; if (BETWEEN(attr[i], 0, 255)) { term.c.attr.bg = attr[i]; } else { fprintf(stderr, "erresc: bad bgcolor %d\n", attr[i]); } - } else { - fprintf(stderr, "erresc(48): gfx attr %d unknown\n", attr[i]); + } else if (i + 4 < l && attr[i + 1] == 2) { + /* RGB color mode: 48;2;R;G;B - silently use first color component */ + i += 4; + if (BETWEEN(attr[i - 2], 0, 255)) { + term.c.attr.bg = attr[i - 2]; /* Use R component as palette index */ + } } break; case 49: @@ -678,7 +689,7 @@ void t_set_attr(int *attr, int l) { } else if (BETWEEN(attr[i], 100, 107)) { term.c.attr.bg = attr[i] - 100 + 8; } else { - fprintf(stderr, "erresc(default): gfx attr %d unknown\n", attr[i]), csi_dump(); + // fprintf(stderr, "erresc(default): gfx attr %d unknown\n", attr[i]), csi_dump(); } break; } @@ -774,14 +785,15 @@ void t_set_mode(bool priv, bool set, int *args, int narg) { case 2004: /* bracketed paste mode */ // MODBIT(term.mode, set, MODE_BRACKETPASTE); break; + case 3: /* DECCOLM -- Column (NOT SUPPORTED) */ + case 4: /* DECSCLM -- Scroll (NOT SUPPORTED) */ + case 69: /* DECVCCM -- Vertical cursor coupling (NOT SUPPORTED) */ + case 1006: /* SGR mouse (NOT SUPPORTED) */ + case 1015: /* URXVT mouse (NOT SUPPORTED) */ + /* Silently ignore unsupported modes */ + break; default: - /* case 2: DECANM -- ANSI/VT52 (NOT SUPPOURTED) */ - /* case 3: DECCOLM -- Column (NOT SUPPORTED) */ - /* case 4: DECSCLM -- Scroll (NOT SUPPORTED) */ - /* case 18: DECPFF -- Printer feed (NOT SUPPORTED) */ - /* case 19: DECPEX -- Printer extent (NOT SUPPORTED) */ - /* case 42: DECNRCM -- National characters (NOT SUPPORTED) */ - fprintf(stderr, "erresc: unknown private set/reset mode %d\n", *args); + /* Other unknown modes - silently ignore */ break; } } else { @@ -800,7 +812,7 @@ void t_set_mode(bool priv, bool set, int *args, int narg) { MODBIT(term.mode, set, MODE_CRLF); break; default: - fprintf(stderr, "erresc: unknown set/reset mode %d\n", *args); + /* Silently ignore unknown modes */ break; } } @@ -854,7 +866,7 @@ void csi_handle(void) { t_move_to(term.c.x, term.c.y + csiescseq.arg[0]); break; case 'c': /* DA -- Device Attributes */ - if (csiescseq.arg[0] == 0) tty_write(VT102ID, sizeof(VT102ID) - 1); + /* Don't respond to DA queries to avoid issues */ break; case 'C': /* CUF -- Cursor Forward */ case 'a': @@ -913,6 +925,13 @@ void csi_handle(void) { case 2: /* all */ t_clear_region(0, 0, term.col - 1, term.row - 1); break; + case 3: /* all including scrollback */ + t_clear_region(0, 0, term.col - 1, term.row - 1); + /* Clear scrollback buffer */ + term.scrollback_count = 0; + term.scrollback_pos = 0; + term.scroll_offset = 0; + break; default: goto unknown; } @@ -992,6 +1011,28 @@ void csi_handle(void) { case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */ t_cursor(CURSOR_LOAD); break; + case 'n': /* DSR -- Device Status Report */ + if (csiescseq.arg[0] == 6) { + /* Report cursor position: ESC[row;colR */ + char buf[32]; + snprintf(buf, sizeof(buf), "\033[%d;%dR", term.c.y + 1, term.c.x + 1); + tty_write(buf, strlen(buf)); + } + break; + case 'p': /* DECSTR -- Soft Terminal Reset (ESC[!p) */ + if (csiescseq.priv) { + /* Reset terminal to initial state */ + t_reset(); + } + break; + case 'b': /* REP -- Repeat last character n times */ + DEFAULT(csiescseq.arg[0], 1); + while (csiescseq.arg[0]-- > 0) { + t_putc(last_char, utf8_size(last_char)); + } + break; + case '%': /* Ignore malformed sequences */ + break; } } @@ -1242,6 +1283,8 @@ void t_putc(char *c, int len) { if (control && !(term.c.attr.mode & ATTR_GFX)) return; if (IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT) t_newline(1); /* always go to first col */ t_set_char(c, &term.c.attr, term.c.x, term.c.y); + /* Store last character for repeat command */ + memcpy(last_char, c, len); if (term.c.x + 1 < term.col) t_move_to(term.c.x + 1, term.c.y); else From a7f3be6656a2745bada300d3d8e33f955f864d49 Mon Sep 17 00:00:00 2001 From: orbisai0security Date: Thu, 14 May 2026 10:45:30 +0000 Subject: [PATCH 5/5] fix: V-003 security vulnerability Automated security fix generated by Orbis Security AI --- src/vt100.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/vt100.c b/src/vt100.c index 401e900..448bad6 100644 --- a/src/vt100.c +++ b/src/vt100.c @@ -178,9 +178,8 @@ void exec_sh(void) { // executing opt_cmd for (int i = 0; i < opt_cmd_size; i++) { - char echo_cmd[255]; - sprintf(echo_cmd, "echo '\n$ %s\n'", opt_cmd[i]); - system(echo_cmd); + printf("\n$ %s\n", opt_cmd[i]); + fflush(stdout); system(opt_cmd[i]); }