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
+15 -4
View File
@@ -852,6 +852,8 @@ public:
*/ */
Fl_Scrollbar *hscrollbar; // horizontal scrollbar Fl_Scrollbar *hscrollbar; // horizontal scrollbar
private: 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) bool fontsize_defer_; // flag defers font calcs until first draw() (issue 837)
int scrollbar_size_; // local preference for scrollbar size int scrollbar_size_; // local preference for scrollbar size
ScrollbarStyle hscrollbar_style_; ScrollbarStyle hscrollbar_style_;
@@ -897,7 +899,6 @@ protected:
private: private:
void create_ring(int drows, int dcols, int hrows); 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); void init_(int X,int Y,int W,int H,const char*L,int rows,int cols,int hist,bool fontsize_defer);
private:
// Tabstops // Tabstops
void init_tabstops(int newsize); void init_tabstops(int newsize);
void default_tabstops(void); void default_tabstops(void);
@@ -999,6 +1000,7 @@ public:
private: private:
void handle_lf(void); void handle_lf(void);
void handle_cr(void); void handle_cr(void);
void handle_esc(void);
// Printing // Printing
void handle_ctrl(char c); void handle_ctrl(char c);
bool is_printable(char c); bool is_printable(char c);
@@ -1168,11 +1170,20 @@ private:
public: public:
float redraw_rate(void) const; float redraw_rate(void) const;
void redraw_rate(float val); 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; bool show_unknown(void) const;
void show_unknown(bool val); 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: public:
// API: ANSI sequences // API: ANSI sequences
bool ansi(void) const; bool ansi(void) const;
+30 -22
View File
@@ -37,12 +37,6 @@
#include <FL/fl_string_functions.h> #include <FL/fl_string_functions.h>
#include "Fl_String.H" #include "Fl_String.H"
/////////////////////////////////
////// Static Class Data ////////
/////////////////////////////////
const char *Fl_Terminal::unknown_char = "¿";
///////////////////////////////// /////////////////////////////////
////// Static Functions ///////// ////// Static Functions /////////
///////////////////////////////// /////////////////////////////////
@@ -181,6 +175,7 @@ bool Fl_Terminal::Selection::get_selection(int &srow,int &scol,
// Always returns true. // Always returns true.
// //
bool Fl_Terminal::Selection::start(int row, int col, bool char_right) { bool Fl_Terminal::Selection::start(int row, int col, bool char_right) {
(void) char_right; // silence warning
srow_ = erow_ = row; srow_ = erow_ = row;
scol_ = ecol_ = col; scol_ = ecol_ = col;
state_ = 1; // state: "started selection" state_ = 1; // state: "started selection"
@@ -2558,6 +2553,16 @@ void Fl_Terminal::handle_lf(void) {
else cursor_down(1, do_scroll); 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. 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 '\r': handle_cr(); return; // CR?
case '\n': handle_lf(); return; // LF? case '\n': handle_lf(); return; // LF?
case '\t': cursor_tab_right(); return; // TAB? case '\t': cursor_tab_right(); return; // TAB?
case 0x1b: if (ansi_) escseq.parse(c); // ESC? case 0x1b: handle_esc(); return; // ESC?
else append_utf8("");
return;
default: handle_unknown_char(); return; // Unknown ctrl char? 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. // NOTE: Use xterm to test. gnome-terminal has bugs, even in 2022.
const bool do_scroll = true; const bool do_scroll = true;
const bool no_scroll = false; 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.. switch (escseq.parse(c)) { // parse char, advance s..
case EscapeSeq::fail: escseq.reset(); return; // failed? reset, done case EscapeSeq::fail: // failed?
case EscapeSeq::success: return; // keep parsing.. escseq.reset(); // ..reset to let error_char be visible
case EscapeSeq::completed: break; // parsed complete esc sequence? 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.. // Shortcut varnames for escseq parsing..
EscapeSeq &esc = escseq; EscapeSeq &esc = escseq;
@@ -3254,7 +3261,7 @@ void Fl_Terminal::append(const char *s, int len/*=-1*/) {
int Fl_Terminal::handle_unknown_char(void) { int Fl_Terminal::handle_unknown_char(void) {
if (!show_unknown_) return 0; if (!show_unknown_) return 0;
escseq.reset(); // disable any pending esc seq to prevent eating unknown char escseq.reset(); // disable any pending esc seq to prevent eating unknown char
print_char(unknown_char); print_char(error_char_);
return 1; return 1;
} }
@@ -3270,9 +3277,9 @@ int Fl_Terminal::handle_unknown_char(void) {
*/ */
int Fl_Terminal::handle_unknown_char(int drow, int dcol) { int Fl_Terminal::handle_unknown_char(int drow, int dcol) {
if (!show_unknown_) return 0; if (!show_unknown_) return 0;
int len = (int)strlen(unknown_char); int len = (int)strlen(error_char_);
Utf8Char *u8c = u8c_disp_row(drow) + dcol; 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; 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 // 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) { 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() scrollbar = hscrollbar = 0; // avoid problems w/update_screen_xywh()
// currently unused params // currently unused params
(void)X; (void)Y; (void)W; (void)H; (void)L; (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. 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 { bool Fl_Terminal::show_unknown(void) const {
return show_unknown_; return show_unknown_;
@@ -4048,12 +4056,12 @@ bool Fl_Terminal::show_unknown(void) const {
/** /**
Set the "show unknown" flag. Set the "show unknown" flag.
If true, unknown escape sequences and unprintable control characters If true, invalid utf8 and invalid ANSI sequences will be shown
will be shown with the error character "¿". 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) { void Fl_Terminal::show_unknown(bool val) {
show_unknown_ = val; show_unknown_ = val;