Improve handling of malformed ANSI. (#950)

This commit is contained in:
Greg Ercolano 2024-08-12 18:00:54 -07:00
parent f74f66e507
commit f825fca43c
2 changed files with 45 additions and 26 deletions

View File

@ -852,6 +852,8 @@ public:
*/
Fl_Scrollbar *hscrollbar; // horizontal scrollbar
private:
// Special utf8 symbols
const char *error_char_; // utf8 string shown for invalid utf8, bad ANSI, etc
bool fontsize_defer_; // flag defers font calcs until first draw() (issue 837)
int scrollbar_size_; // local preference for scrollbar size
ScrollbarStyle hscrollbar_style_;
@ -897,7 +899,6 @@ protected:
private:
void create_ring(int drows, int dcols, int hrows);
void init_(int X,int Y,int W,int H,const char*L,int rows,int cols,int hist,bool fontsize_defer);
private:
// Tabstops
void init_tabstops(int newsize);
void default_tabstops(void);
@ -999,6 +1000,7 @@ public:
private:
void handle_lf(void);
void handle_cr(void);
void handle_esc(void);
// Printing
void handle_ctrl(char c);
bool is_printable(char c);
@ -1168,11 +1170,20 @@ private:
public:
float redraw_rate(void) const;
void redraw_rate(float val);
// API: Show unknown/unprintable chars
// API: Show unknown/invalid utf8/ANSI sequences with an error character (¿).
bool show_unknown(void) const;
void show_unknown(bool val);
protected:
static const char *unknown_char; ///< "unknown" replacement character
/** Sets the "error character" utf8 string shown for invalid utf8
or bad ANSI sequences if show_unknown() is true. Default: "¿".
\See show_unknown(bool)
*/
void error_char(const char* val) { error_char_ = val; }
/** Returns the "error character" utf8 string, which is shown for invalid utf8
or bad ANSI sequences if show_unknown() is true. \See show_unknown(bool)
*/
const char* error_char(void) const { return error_char_; }
public:
// API: ANSI sequences
bool ansi(void) const;

View File

@ -37,12 +37,6 @@
#include <FL/fl_string_functions.h>
#include "Fl_String.H"
/////////////////////////////////
////// Static Class Data ////////
/////////////////////////////////
const char *Fl_Terminal::unknown_char = "¿";
/////////////////////////////////
////// Static Functions /////////
/////////////////////////////////
@ -181,6 +175,7 @@ bool Fl_Terminal::Selection::get_selection(int &srow,int &scol,
// Always returns true.
//
bool Fl_Terminal::Selection::start(int row, int col, bool char_right) {
(void) char_right; // silence warning
srow_ = erow_ = row;
scol_ = ecol_ = col;
state_ = 1; // state: "started selection"
@ -2558,6 +2553,16 @@ void Fl_Terminal::handle_lf(void) {
else cursor_down(1, do_scroll);
}
// Handle '\e' escape character.
void Fl_Terminal::handle_esc(void) {
if (!ansi_) // not in ansi mode?
{ handle_unknown_char(); return; } // ..show unknown char, early exit
if (escseq.esc_mode() == 0x1b) // already in esc mode?
{ handle_unknown_char(); } // ..show 1st esc as unknown char, parse 2nd
if (escseq.parse(0x1b) == EscapeSeq::fail) // parse esc
{ handle_unknown_char(); return; } // ..error? show unknown char
}
/**
Sets the combined output translation flags to \p val.
@ -2599,9 +2604,7 @@ void Fl_Terminal::handle_ctrl(char c) {
case '\r': handle_cr(); return; // CR?
case '\n': handle_lf(); return; // LF?
case '\t': cursor_tab_right(); return; // TAB?
case 0x1b: if (ansi_) escseq.parse(c); // ESC?
else append_utf8("");
return;
case 0x1b: handle_esc(); return; // ESC?
default: handle_unknown_char(); return; // Unknown ctrl char?
}
}
@ -2731,12 +2734,16 @@ void Fl_Terminal::handle_escseq(char c) {
// NOTE: Use xterm to test. gnome-terminal has bugs, even in 2022.
const bool do_scroll = true;
const bool no_scroll = false;
//UNUSED const bool do_wrap = true;
//UNUSED const bool no_wrap = false;
switch (escseq.parse(c)) { // parse char, advance s..
case EscapeSeq::fail: escseq.reset(); return; // failed? reset, done
case EscapeSeq::success: return; // keep parsing..
case EscapeSeq::completed: break; // parsed complete esc sequence?
case EscapeSeq::fail: // failed?
escseq.reset(); // ..reset to let error_char be visible
handle_unknown_char(); // ..show error char (if enabled)
print_char(c); // ..show char we couldn't handle
return; // ..done.
case EscapeSeq::success: // success?
return; // ..keep parsing
case EscapeSeq::completed: // parsed complete esc sequence?
break; // ..fall through to handle operation
}
// Shortcut varnames for escseq parsing..
EscapeSeq &esc = escseq;
@ -3254,7 +3261,7 @@ void Fl_Terminal::append(const char *s, int len/*=-1*/) {
int Fl_Terminal::handle_unknown_char(void) {
if (!show_unknown_) return 0;
escseq.reset(); // disable any pending esc seq to prevent eating unknown char
print_char(unknown_char);
print_char(error_char_);
return 1;
}
@ -3270,9 +3277,9 @@ int Fl_Terminal::handle_unknown_char(void) {
*/
int Fl_Terminal::handle_unknown_char(int drow, int dcol) {
if (!show_unknown_) return 0;
int len = (int)strlen(unknown_char);
int len = (int)strlen(error_char_);
Utf8Char *u8c = u8c_disp_row(drow) + dcol;
u8c->text_utf8(unknown_char, len, *current_style_);
u8c->text_utf8(error_char_, len, *current_style_);
return 1;
}
@ -3384,6 +3391,7 @@ Fl_Terminal::Fl_Terminal(int X,int Y,int W,int H,const char*L,int rows,int cols,
// Private constructor method
void Fl_Terminal::init_(int X,int Y,int W,int H,const char*L,int rows,int cols,int hist,bool fontsize_defer) {
error_char_ = "¿";
scrollbar = hscrollbar = 0; // avoid problems w/update_screen_xywh()
// currently unused params
(void)X; (void)Y; (void)W; (void)H; (void)L;
@ -4039,7 +4047,7 @@ void Fl_Terminal::redraw_rate(float val) {
/**
Return the "show unknown" flag.
See show_unknown(bool) for more info.
\See show_unknown(bool), error_char(const char*).
*/
bool Fl_Terminal::show_unknown(void) const {
return show_unknown_;
@ -4048,12 +4056,12 @@ bool Fl_Terminal::show_unknown(void) const {
/**
Set the "show unknown" flag.
If true, unknown escape sequences and unprintable control characters
will be shown with the error character "¿".
If true, invalid utf8 and invalid ANSI sequences will be shown
with the error character "¿".
If false, those sequences and characters will be ignored.
If false, errors characters won't be shown.
\see handle_unknown_char()
\see handle_unknown_char(), error_char(const char*).
*/
void Fl_Terminal::show_unknown(bool val) {
show_unknown_ = val;