Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libtsm for openSUSE:Factory checked in at 2026-08-21 17:01:41 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libtsm (Old) and /work/SRC/openSUSE:Factory/.libtsm.new.1258 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libtsm" Fri Aug 21 17:01:41 2026 rev:10 rq:1372853 version:4.7.1 Changes: -------- --- /work/SRC/openSUSE:Factory/libtsm/libtsm.changes 2026-07-07 21:09:38.387649219 +0200 +++ /work/SRC/openSUSE:Factory/.libtsm.new.1258/libtsm.changes 2026-08-21 17:03:16.040186290 +0200 @@ -1,0 +2,12 @@ +Fri Aug 21 08:11:15 UTC 2026 - Adam Mizerski <[email protected]> + +- update to 4.7.1 + * libtsm: fix tsm_screen_attr2_t + * Fix 3 out of bound reads +- update to 4.7.0 + * Fix backward selection + * Fix: also clear the character value for multi-width character. + * screen/vte: add cursor style support via DECSCUSR (CSI Ps SP q) + * screen: don't clear cells when resizing + +------------------------------------------------------------------- Old: ---- v4.6.0.tar.gz New: ---- v4.7.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libtsm.spec ++++++ --- /var/tmp/diff_new_pack.c2Dij3/_old 2026-08-21 17:03:16.744211216 +0200 +++ /var/tmp/diff_new_pack.c2Dij3/_new 2026-08-21 17:03:16.746211287 +0200 @@ -19,7 +19,7 @@ %global sover 4 %global lname libtsm%{sover} Name: libtsm -Version: 4.6.0 +Version: 4.7.1 Release: 0 Summary: DEC-VT terminal emulator state machine License: LGPL-2.1-or-later AND MIT ++++++ v4.6.0.tar.gz -> v4.7.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtsm-4.6.0/NEWS.md new/libtsm-4.7.1/NEWS.md --- old/libtsm-4.6.0/NEWS.md 2026-06-22 18:08:24.000000000 +0200 +++ new/libtsm-4.7.1/NEWS.md 2026-08-14 14:45:17.000000000 +0200 @@ -1,5 +1,26 @@ # libtsm Release News +## CHANGES WITH 4.7.1 +### Bug fixes +* libtsm: fix tsm_screen_attr2_t by @kdj0c in https://github.com/kmscon/libtsm/pull/64 +* Fix 3 out of bound reads by @kdj0c in https://github.com/kmscon/libtsm/pull/65 + +## CHANGES WITH 4.7.0 +### New cursor interface: +A new tsm_screen_get_cursor_style() interface is available, that provides the current +style of the cursor. + +### New features +* screen/vte: add cursor style support via DECSCUSR (CSI Ps SP q) by @underscoreevelyn in https://github.com/kmscon/libtsm/pull/58 + +### Bug Fixes +* Fix backward selection by @kdj0c in https://github.com/kmscon/libtsm/pull/54 +* Fix also clear the character value for multi-width character. by @kdj0c in https://github.com/kmscon/libtsm/pull/56 +* screen: don't clear cells when resizing by @kdj0c in https://github.com/kmscon/libtsm/pull/61 + +## New Contributors +* @underscoreevelyn made their first contribution in https://github.com/kmscon/libtsm/pull/58 + ## CHANGES WITH 4.6.0 ### New draw2 interface A new tsm_screen_draw2() interface is available that provides a simplified drawing API. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtsm-4.6.0/meson.build new/libtsm-4.7.1/meson.build --- old/libtsm-4.6.0/meson.build 2026-06-22 18:08:24.000000000 +0200 +++ new/libtsm-4.7.1/meson.build 2026-08-14 14:45:17.000000000 +0200 @@ -3,7 +3,7 @@ project( 'libtsm', 'c', - version: '4.6.0', + version: '4.7.1', license: 'MIT', meson_version: '>=1.1', default_options: [ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtsm-4.6.0/src/tsm/libtsm-int.h new/libtsm-4.7.1/src/tsm/libtsm-int.h --- old/libtsm-4.6.0/src/tsm/libtsm-int.h 2026-06-22 18:08:24.000000000 +0200 +++ new/libtsm-4.7.1/src/tsm/libtsm-int.h 2026-08-14 14:45:17.000000000 +0200 @@ -127,34 +127,37 @@ struct tsm_screen_attr def_attr_main; /* ageing */ - tsm_age_t age_cnt; /* current age counter */ - unsigned int age_reset : 1; /* age-overflow flag */ + tsm_age_t age_cnt; /* current age counter */ + unsigned int age_reset : 1; /* age-overflow flag */ /* current buffer */ - unsigned int size_x; /* width of screen */ - unsigned int size_y; /* height of screen */ - unsigned int margin_top; /* top-margin index */ - unsigned int margin_bottom; /* bottom-margin index */ - unsigned int line_num; /* real number of allocated lines */ - struct line **lines; /* active lines; copy of main/alt */ - struct line **main_lines; /* real main lines */ - struct line **alt_lines; /* real alternative lines */ - tsm_age_t age; /* whole screen age */ + unsigned int size_x; /* width of screen */ + unsigned int size_y; /* height of screen */ + unsigned int margin_top; /* top-margin index */ + unsigned int margin_bottom; /* bottom-margin index */ + unsigned int line_num; /* real number of allocated lines */ + struct line **lines; /* active lines; copy of main/alt */ + struct line **main_lines; /* real main lines */ + struct line **alt_lines; /* real alternative lines */ + tsm_age_t age; /* whole screen age */ struct tsm_scrollback sb; /* cursor: positions are always in-bound, but cursor_x might be * bigger than size_x if new-line is pending */ - unsigned int cursor_x; /* current cursor x-pos */ - unsigned int cursor_y; /* current cursor y-pos */ + unsigned int cursor_x; /* current cursor x-pos */ + unsigned int cursor_y; /* current cursor y-pos */ + + enum tsm_screen_cursor_style cstyle; /* cursor shape */ /* tab ruler */ - bool *tab_ruler; /* tab-flag for all cells of one row */ + bool *tab_ruler; /* tab-flag for all cells of one row */ /* selection */ bool sel_active; - struct selection_pos sel_start; - struct selection_pos sel_end; + struct selection_pos sel_begin; /* First cell selected */ + struct selection_pos sel_start; /* First cell to copy in terminal order */ + struct selection_pos sel_end; /* Last cell to copy */ /* draw2 interface */ struct tsm_screen_cell *cells; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtsm-4.6.0/src/tsm/libtsm.h new/libtsm-4.7.1/src/tsm/libtsm.h --- old/libtsm-4.6.0/src/tsm/libtsm.h 2026-06-22 18:08:24.000000000 +0200 +++ new/libtsm-4.7.1/src/tsm/libtsm.h 2026-08-14 14:45:17.000000000 +0200 @@ -180,7 +180,7 @@ uint8_t italic : 1; uint8_t underline : 1; uint8_t blink : 1; - uint8_t reserved : 5; + uint8_t reserved : 4; }; uint8_t u8; } tsm_screen_attr2_t; @@ -198,6 +198,16 @@ tsm_screen_attr2_t attr2; /* glyph attributes */ }; +enum tsm_screen_cursor_style { + TSM_SCREEN_CURSOR_DEFAULT = 0, + TSM_SCREEN_CURSOR_BLOCK_BLINK = 1, + TSM_SCREEN_CURSOR_BLOCK_STEADY = 2, + TSM_SCREEN_CURSOR_UNDERLINE_BLINK = 3, + TSM_SCREEN_CURSOR_UNDERLINE_STEADY = 4, + TSM_SCREEN_CURSOR_VBAR_BLINK = 5, + TSM_SCREEN_CURSOR_VBAR_STEADY = 6, +}; + typedef int (*tsm_screen_draw_cb) (struct tsm_screen *con, uint64_t id, const uint32_t *ch, @@ -296,6 +306,9 @@ const struct tsm_screen_cell *tsm_screen_draw2(struct tsm_screen *con); +enum tsm_screen_cursor_style tsm_screen_get_cursor_style(struct tsm_screen *con); +void tsm_screen_set_cursor_style(struct tsm_screen *con, enum tsm_screen_cursor_style type); + /** @} */ /** diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtsm-4.6.0/src/tsm/libtsm.sym new/libtsm-4.7.1/src/tsm/libtsm.sym --- old/libtsm-4.6.0/src/tsm/libtsm.sym 2026-06-22 18:08:24.000000000 +0200 +++ new/libtsm-4.7.1/src/tsm/libtsm.sym 2026-08-14 14:45:17.000000000 +0200 @@ -153,3 +153,9 @@ global: tsm_screen_draw2; } LIBTSM_4_5; + +LIBTSM_4_7 { +global: + tsm_screen_get_cursor_style; + tsm_screen_set_cursor_style; +} LIBTSM_4_6; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtsm-4.6.0/src/tsm/tsm-screen.c new/libtsm-4.7.1/src/tsm/tsm-screen.c --- old/libtsm-4.6.0/src/tsm/tsm-screen.c 2026-06-22 18:08:24.000000000 +0200 +++ new/libtsm-4.7.1/src/tsm/tsm-screen.c 2026-08-14 14:45:17.000000000 +0200 @@ -191,6 +191,8 @@ { if (!con->sel_active) return; + if (con->sel_begin.line == line) + con->sel_begin.line = NULL; if (con->sel_start.line == line) con->sel_start.line = NULL; if (con->sel_end.line == line) @@ -241,7 +243,6 @@ static void remove_from_sb(struct tsm_screen *con, unsigned int num) { struct line *tmp; - int i, copy_len; /* TODO: more sophisticated ageing */ con->age = con->age_cnt; @@ -254,30 +255,24 @@ while (num--) { tmp = shl_dlist_last(&con->sb.list, struct line, list); + + if (tmp->size < con->size_x) + if (line_resize(con, tmp, con->size_x) < 0) + goto end_sbpos; shl_dlist_unlink(&tmp->list); --con->sb.count; if (con->sb.pos == tmp) { con->sb.pos_num = con->sb.count; - con->sb.pos = NULL; + con->sb.pos = NULL; } - /* - * Copy the cells from the scrollback buffer to the line. scrollback buffer can have a different - * size as current lines, because resizing doesn't resize lines in scrollback buffer. - */ - copy_len = shl_min(tmp->size, con->lines[num]->size); - memcpy(con->lines[num]->cells, tmp->cells, copy_len * sizeof(struct cell)); - for (i = copy_len; i < con->size_x; i++) - screen_cell_init(con, &con->lines[num]->cells[i]); + clear_selection_on_line(con, con->lines[num]); + line_free(con->lines[num]); + tmp->sb_id = 0; + con->lines[num] = tmp; con->lines[num]->age = con->age_cnt; - - if (con->sel_active && con->sel_start.line == tmp) - con->sel_start.line = con->lines[num]; - if (con->sel_active && con->sel_end.line == tmp) - con->sel_end.line = con->lines[num]; - - line_free(tmp); } +end_sbpos: if (!con->sb.pos) con->sb.pos_num = con->sb.count; } @@ -403,6 +398,7 @@ for (i = 1; i < len && i + x < con->size_x; ++i) { line->cells[x + i].age = con->age_cnt; line->cells[x + i].width = 0; + line->cells[x + i].ch = 0; } } @@ -594,7 +590,7 @@ unsigned int y) { struct line **cache; - unsigned int i, j, width, diff, start; + unsigned int i, width, diff; int ret; bool *tab_ruler; @@ -674,29 +670,6 @@ screen_inc_age(con); - /* clear expansion/padding area */ - start = x; - if (x > con->size_x) - start = con->size_x; - for (j = 0; j < con->line_num; ++j) { - /* main-lines may go into SB, so clear all cells */ - i = 0; - if (j < con->size_y) - i = start; - - for ( ; i < con->main_lines[j]->size; ++i) - screen_cell_init_generic(con, &con->main_lines[j]->cells[i], - &con->def_attr_main); - - /* alt-lines never go into SB, only clear visible cells */ - i = 0; - if (j < con->size_y) - i = con->size_x; - - for ( ; i < x; ++i) - screen_cell_init(con, &con->alt_lines[j]->cells[i]); - } - /* xterm destroys margins on resize, so do we */ con->margin_top = 0; con->margin_bottom = con->size_y - 1; @@ -840,9 +813,11 @@ con->age = con->age_cnt; if (con->sel_active) { + if (con->sel_begin.line && is_in_scrollback(&con->sel_begin)) + con->sel_begin.line = NULL; if (con->sel_start.line && is_in_scrollback(&con->sel_start)) con->sel_start.line = NULL; - if (con->sel_end.line && is_in_scrollback(&con->sel_end)) + if (con->sel_end.line && is_in_scrollback(&con->sel_end)) con->sel_end.line = NULL; } shl_dlist_for_each_safe(iter, safe, &con->sb.list) { @@ -1374,6 +1349,11 @@ screen_inc_age(con); x = con->cursor_x; + + /* cursor_x may exceed size_x (e.g. CHT then a wide glyph at the last + * column); clamp before indexing tab_ruler[0..size_x-1]. */ + if (x > con->size_x) + x = con->size_x; for (i = 0; i < num; ++i) { for (j = x - 1; j > 0; --j) { if (con->tab_ruler[j]) @@ -1692,3 +1672,21 @@ screen_erase_region(con, 0, 0, con->size_x - 1, con->size_y - 1, protect); } + +SHL_EXPORT +enum tsm_screen_cursor_style tsm_screen_get_cursor_style(struct tsm_screen *con) +{ + if (!con) + return 0; + + return con->cstyle; +} + +SHL_EXPORT +void tsm_screen_set_cursor_style(struct tsm_screen *con, enum tsm_screen_cursor_style type) +{ + if (!con) + return; + + con->cstyle = type; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtsm-4.6.0/src/tsm/tsm-selection.c new/libtsm-4.7.1/src/tsm/tsm-selection.c --- old/libtsm-4.6.0/src/tsm/tsm-selection.c 2026-06-22 18:08:24.000000000 +0200 +++ new/libtsm-4.7.1/src/tsm/tsm-selection.c 2026-08-14 14:45:17.000000000 +0200 @@ -175,55 +175,32 @@ return pos - buf; } -static void swap_selections(struct tsm_screen *con) -{ - struct selection_pos c; - - c = con->sel_start; - con->sel_start = con->sel_end; - con->sel_end = c; -} - /* - * Normalize a selection - * - * Start must always point to the top left and end to the bottom right cell + * Returns true if a is before b in terminal order */ -static void norm_selection(struct tsm_screen *con) +static bool selection_is_before(struct tsm_screen *con, struct selection_pos *a, struct selection_pos *b) { int i; - struct selection_pos *start, *end; - - start = &con->sel_start; - end = &con->sel_end; - if (start->line == end->line) { - if (con->sel_start.x > con->sel_end.x) - swap_selections(con); - return; - } + if (a->line == b->line) + return (a->x < b->x); - if (is_in_scrollback(&con->sel_start) != is_in_scrollback(&con->sel_end)) { - if (is_in_scrollback(&con->sel_end)) - swap_selections(con); - return; - } + if (is_in_scrollback(a) != is_in_scrollback(b)) + return (is_in_scrollback(a)); - if (is_in_scrollback(&con->sel_start) && is_in_scrollback(&con->sel_end)) { - if (con->sel_start.line->sb_id > con->sel_end.line->sb_id) - swap_selections(con); - return; - } + if (is_in_scrollback(a) && is_in_scrollback(b)) + return (a->line->sb_id < b->line->sb_id); - /* so both are not in scroll back buffer and can't be equal */ + /* so both are not in scroll back buffer and are not on the same line */ for (i = 0; i < con->size_y; i++) { - if (con->lines[i] == con->sel_end.line) { - swap_selections(con); - return; - } - if (con->lines[i] == con->sel_start.line) - return; + if (con->lines[i] == b->line) + return false; + + if (con->lines[i] == a->line) + return true; } + // Should not happen + return true; } SHL_EXPORT @@ -239,8 +216,9 @@ con->age = con->age_cnt; con->sel_active = true; - selection_set(con, &con->sel_start, posx, posy); - memcpy(&con->sel_end, &con->sel_start, sizeof(con->sel_end)); + selection_set(con, &con->sel_begin, posx, posy); + con->sel_start = con->sel_begin; + con->sel_end = con->sel_begin; } SHL_EXPORT @@ -248,6 +226,8 @@ unsigned int posx, unsigned int posy) { + struct selection_pos target; + if (!con || !con->sel_active || posx >= con->size_x || posy >= con->size_y) return; @@ -255,9 +235,14 @@ /* TODO: more sophisticated ageing */ con->age = con->age_cnt; - selection_set(con, &con->sel_end, posx, posy); - /* always normalize the selection */ - norm_selection(con); + selection_set(con, &target, posx, posy); + if (selection_is_before(con, &con->sel_begin, &target)) { + con->sel_start = con->sel_begin; + con->sel_end = target; + } else { + con->sel_start = target; + con->sel_end = con->sel_begin; + } } SHL_EXPORT @@ -284,7 +269,7 @@ static unsigned int get_line_index(struct tsm_screen *con, struct line *line) { unsigned int i = 0; - + if (line->sb_id) return 0; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtsm-4.6.0/src/tsm/tsm-vte.c new/libtsm-4.7.1/src/tsm/tsm-vte.c --- old/libtsm-4.6.0/src/tsm/tsm-vte.c 2026-06-22 18:08:24.000000000 +0200 +++ new/libtsm-4.7.1/src/tsm/tsm-vte.c 2026-08-14 14:45:17.000000000 +0200 @@ -143,6 +143,7 @@ struct tsm_screen_attr cattr; tsm_vte_charset **gl; tsm_vte_charset **gr; + enum tsm_screen_cursor_style cursor_style; bool wrap_mode; bool origin_mode; }; @@ -782,6 +783,7 @@ vte->saved_state.wrap_mode = true; vte->saved_state.gl = &vte->g0; vte->saved_state.gr = &vte->g1; + vte->saved_state.cursor_style = TSM_SCREEN_CURSOR_DEFAULT; copy_fcolor(&vte->saved_state.cattr, &vte->def_attr); copy_bcolor(&vte->saved_state.cattr, &vte->def_attr); @@ -803,6 +805,7 @@ vte->saved_state.gr = vte->gr; vte->saved_state.wrap_mode = vte->flags & TSM_VTE_FLAG_AUTO_WRAP_MODE; vte->saved_state.origin_mode = vte->flags & TSM_VTE_FLAG_ORIGIN_MODE; + vte->saved_state.cursor_style = tsm_screen_get_cursor_style(vte->con); } static void restore_state(struct tsm_vte *vte) @@ -815,6 +818,7 @@ tsm_screen_set_def_attr(vte->con, &vte->cattr); vte->gl = vte->saved_state.gl; vte->gr = vte->saved_state.gr; + tsm_screen_set_cursor_style(vte->con, vte->saved_state.cursor_style); if (vte->saved_state.wrap_mode) { vte->flags |= TSM_VTE_FLAG_AUTO_WRAP_MODE; @@ -1302,6 +1306,12 @@ static void lookup_color(struct tsm_vte *vte, int color, uint8_t *cr, uint8_t *cg, uint8_t *cb) { + /* OSC-4 / SGR color indices are untrusted; an out-of-range (or + * unsigned-overflow-negative) index would wild-read palette[]/bval[]. */ + if (color < 0 || color > 255) { + *cr = *cg = *cb = 0; + return; + } if (color < 16) { palette_rgb(vte, color, cr, cg, cb); } else if (color < 232) { @@ -1475,6 +1485,10 @@ /* fallthrough */ case 48: val = vte->csi_argv[i]; + /* the 5/2 subcommand + its operands live in later argv slots; + * bail if they would read past the parsed args (csi_argv[16] OOB). */ + if (i + 1 >= vte->csi_argc) + break; if (vte->csi_argv[i + 1] == 5) { // 256color mode if (i + 2 >= vte->csi_argc || vte->csi_argv[i + 2] < 0) { @@ -2134,21 +2148,28 @@ num = vte->csi_argv[0]; tsm_screen_repeat_char(vte->con, num); break; - case 'q': /* DECLL - Load LEDs */ - num = vte->csi_argv[0]; - if (num <= 0) { - vte->led_state = 0; - } else if (num == 1) { - vte->led_state |= TSM_VTE_LED_SCROLL_LOCK; - } else if (num == 2) { - vte->led_state |= TSM_VTE_LED_NUM_LOCK; - } else if (num == 3) { - vte->led_state |= TSM_VTE_LED_CAPS_LOCK; + case 'q': /* DECLL - Load LEDs / DECSCUSR - Set Cursor Style */ + if (vte->csi_flags & CSI_SPACE) { + num = vte->csi_argv[0]; + if (num < 0) + num = 0; + tsm_screen_set_cursor_style(vte->con, num); } else { - break; + num = vte->csi_argv[0]; + if (num <= 0) { + vte->led_state = 0; + } else if (num == 1) { + vte->led_state |= TSM_VTE_LED_SCROLL_LOCK; + } else if (num == 2) { + vte->led_state |= TSM_VTE_LED_NUM_LOCK; + } else if (num == 3) { + vte->led_state |= TSM_VTE_LED_CAPS_LOCK; + } else { + break; + } + if (vte->led_cb) + vte->led_cb(vte, vte->led_state, vte->led_data); } - if (vte->led_cb) - vte->led_cb(vte, vte->led_state, vte->led_data); break; default: llog_debug(vte, "unhandled CSI sequence %c", data);
