From d126c4996ab0d3cebcb874222ae673fb0476a881 Mon Sep 17 00:00:00 2001 From: Markus Gans Date: Tue, 31 Dec 2019 06:32:51 +0100 Subject: [PATCH] Adding an ANSI X3.64 SGR optimizer --- ChangeLog | 5 + examples/background-color.cpp | 22 ++- src/Makefile.am | 2 + src/Makefile.clang | 2 + src/Makefile.gcc | 2 + src/fapplication.cpp | 8 +- src/foptiattr.cpp | 16 +- src/fstartoptions.cpp | 1 + src/ftermcapquirks.cpp | 6 +- src/include/final/final.h | 1 + src/include/final/foptiattr.h | 293 +++++++++++++++--------------- src/include/final/fstartoptions.h | 3 +- src/include/final/sgr_optimizer.h | 93 ++++++++++ src/sgr_optimizer.cpp | 156 ++++++++++++++++ test/foptiattr-test.cpp | 155 ++++++++++++++++ 15 files changed, 604 insertions(+), 161 deletions(-) create mode 100644 src/include/final/sgr_optimizer.h create mode 100644 src/sgr_optimizer.cpp diff --git a/ChangeLog b/ChangeLog index 03c61026..87c3678d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2019-12-31 Markus Gans + * The new SGRoptimizer class allows several consecutive parameters + from the SGR (Select Graphic Rendition) attributes to be combined + into one + 2019-12-23 Markus Gans * Correction for height and width alignment in adjustSize() * Better setSize() implementation in some widgets diff --git a/examples/background-color.cpp b/examples/background-color.cpp index 79c7570a..3139557e 100644 --- a/examples/background-color.cpp +++ b/examples/background-color.cpp @@ -127,10 +127,13 @@ Background::Background (finalcut::FWidget* parent) blue.setValue (0xec); // Set the initial palette values - finalcut::FTerm::setPalette ( finalcut::fc::LightMagenta - , int(red.getValue()) - , int(green.getValue()) - , int(blue.getValue()) ); + if ( finalcut::FTerm::canChangeColorPalette() ) + { + finalcut::FTerm::setPalette ( finalcut::fc::LightMagenta + , int(red.getValue()) + , int(green.getValue()) + , int(blue.getValue()) ); + } // Quit button quit.setGeometry(FPoint(19, 8), FSize(10, 1)); @@ -168,6 +171,9 @@ Background::~Background() // destructor //---------------------------------------------------------------------- void Background::cb_changed (finalcut::FWidget*, FDataPtr) { + if ( ! finalcut::FTerm::canChangeColorPalette() ) + return; + finalcut::FTerm::setPalette ( finalcut::fc::LightMagenta , int(red.getValue()) , int(green.getValue()) @@ -179,6 +185,9 @@ void Background::cb_changed (finalcut::FWidget*, FDataPtr) //---------------------------------------------------------------------- void Background::cb_choice (finalcut::FWidget*, FDataPtr) { + if ( ! finalcut::FTerm::canChangeColorPalette() ) + return; + uChar r{}, g{}, b{}; FDataPtr data_ptr = color_choice.getItemData(); RGB* rgb = reinterpret_cast(data_ptr); @@ -202,7 +211,10 @@ void Background::cb_choice (finalcut::FWidget*, FDataPtr) int main (int argc, char* argv[]) { finalcut::FApplication app(argc, argv); - app.setBackgroundColor(finalcut::fc::LightMagenta); + + if ( finalcut::FTerm::canChangeColorPalette() ) + app.setBackgroundColor(finalcut::fc::LightMagenta); + Background dialog(&app); app.setMainWidget(&dialog); dialog.show(); diff --git a/src/Makefile.am b/src/Makefile.am index 8271087f..d9cdb25f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,6 +62,7 @@ libfinal_la_SOURCES = \ ftextview.cpp \ fvterm.cpp \ fevent.cpp \ + sgr_optimizer.cpp \ foptiattr.cpp \ foptimove.cpp \ ftermbuffer.cpp \ @@ -111,6 +112,7 @@ finalcutinclude_HEADERS = \ include/final/fobject.h \ include/final/fpoint.h \ include/final/fsize.h \ + include/final/sgr_optimizer.h \ include/final/foptiattr.h \ include/final/foptimove.h \ include/final/ftermbuffer.h \ diff --git a/src/Makefile.clang b/src/Makefile.clang index 518bddb1..c2696ce2 100644 --- a/src/Makefile.clang +++ b/src/Makefile.clang @@ -31,6 +31,7 @@ INCLUDE_HEADERS = \ fcheckmenuitem.h \ fmessagebox.h \ ftooltip.h \ + sgr_optimizer.h \ foptiattr.h \ foptimove.h \ ftermbuffer.h \ @@ -132,6 +133,7 @@ OBJS = \ ftermopenbsd.o \ ftermlinux.o \ fvterm.o \ + sgr_optimizer.o \ foptiattr.o \ foptimove.o \ ftermbuffer.o \ diff --git a/src/Makefile.gcc b/src/Makefile.gcc index eb8e67c2..4a1578b3 100644 --- a/src/Makefile.gcc +++ b/src/Makefile.gcc @@ -31,6 +31,7 @@ INCLUDE_HEADERS = \ fcheckmenuitem.h \ fmessagebox.h \ ftooltip.h \ + sgr_optimizer.h \ foptiattr.h \ foptimove.h \ ftermbuffer.h \ @@ -132,6 +133,7 @@ OBJS = \ ftermopenbsd.o \ ftermlinux.o \ fvterm.o \ + sgr_optimizer.o \ foptiattr.o \ foptimove.o \ ftermbuffer.o \ diff --git a/src/fapplication.cpp b/src/fapplication.cpp index 4b3c9ffd..11b9f3f1 100644 --- a/src/fapplication.cpp +++ b/src/fapplication.cpp @@ -320,6 +320,8 @@ void FApplication::showParameterUsage() << " Disable terminal detection\n" << " --no-color-change " << " Do not redefine the color palette\n" + << " --no-sgr-optimizer " + << " Do not optimize SGR sequences\n" << " --vgafont " << " Set the standard vga 8x16 font\n" << " --newfont " @@ -415,6 +417,7 @@ void FApplication::cmd_options (const int& argc, char* argv[]) {C_STR("no-optimized-cursor"), no_argument, 0, 0 }, {C_STR("no-terminal-detection"), no_argument, 0, 0 }, {C_STR("no-color-change"), no_argument, 0, 0 }, + {C_STR("no-sgr-optimizer"), no_argument, 0, 0 }, {C_STR("vgafont"), no_argument, 0, 0 }, {C_STR("newfont"), no_argument, 0, 0 }, @@ -469,6 +472,9 @@ void FApplication::cmd_options (const int& argc, char* argv[]) if ( std::strcmp(long_options[idx].name, "no-color-change") == 0 ) getStartOptions().color_change = false; + if ( std::strcmp(long_options[idx].name, "no-sgr-optimizer") == 0 ) + getStartOptions().sgr_optimizer = false; + if ( std::strcmp(long_options[idx].name, "vgafont") == 0 ) getStartOptions().vgafont = true; @@ -819,7 +825,7 @@ void FApplication::closeDropDown() { // Close the open menu - if ( mouse && mouse->isMoved() ) + if ( ! mouse || (mouse && mouse->isMoved()) ) return; const auto& mouse_position = mouse->getPos(); diff --git a/src/foptiattr.cpp b/src/foptiattr.cpp index fa2761fc..68085af2 100644 --- a/src/foptiattr.cpp +++ b/src/foptiattr.cpp @@ -24,6 +24,7 @@ #include "final/fc.h" #include "final/foptiattr.h" +#include "final/fstartoptions.h" namespace finalcut { @@ -578,6 +579,9 @@ char* FOptiAttr::changeAttribute (FChar*& term, FChar*& next) changeAttributeSeparately (term, next); } + if ( FStartOptions::getFStartOptions().sgr_optimizer ) + sgr_optimizer.optimize(); + return attr_buf; } @@ -1651,14 +1655,12 @@ inline bool FOptiAttr::switchOff() //---------------------------------------------------------------------- inline bool FOptiAttr::append_sequence (char seq[]) { - if ( seq ) - { - std::strncat (attr_ptr, seq, sizeof(attr_buf) - std::strlen(attr_ptr)); - attr_buf[sizeof(attr_buf) - 1] = '\0'; - return true; - } - else + if ( ! seq ) return false; + + std::strncat (attr_ptr, seq, sizeof(attr_buf) - std::strlen(attr_ptr)); + attr_buf[sizeof(attr_buf) - 1] = '\0'; + return true; } } // namespace finalcut diff --git a/src/fstartoptions.cpp b/src/fstartoptions.cpp index 3c1b9c5d..da7658ed 100644 --- a/src/fstartoptions.cpp +++ b/src/fstartoptions.cpp @@ -39,6 +39,7 @@ FStartOptions::FStartOptions() , mouse_support{true} , terminal_detection{true} , color_change{true} + , sgr_optimizer{true} , vgafont{false} , newfont{false} , encoding{fc::UNKNOWN} diff --git a/src/ftermcapquirks.cpp b/src/ftermcapquirks.cpp index f18d51d9..64e8a28b 100644 --- a/src/ftermcapquirks.cpp +++ b/src/ftermcapquirks.cpp @@ -201,9 +201,9 @@ void FTermcapQuirks::linux() "%?%p4%t;5%;m" "%?%p9%t\016%e\017%;"); - TCAP(fc::t_enter_alt_charset_mode) = C_STR("\016"); - TCAP(fc::t_exit_alt_charset_mode) = C_STR("\017"); - TCAP(fc::t_exit_attribute_mode) = C_STR(CSI "0m\017"); + TCAP(fc::t_enter_alt_charset_mode) = C_STR(SO); + TCAP(fc::t_exit_alt_charset_mode) = C_STR(SI); + TCAP(fc::t_exit_attribute_mode) = C_STR(CSI "0m" SI); TCAP(fc::t_exit_bold_mode) = C_STR(CSI "22m"); TCAP(fc::t_exit_blink_mode) = C_STR(CSI "25m"); TCAP(fc::t_exit_reverse_mode) = C_STR(CSI "27m"); diff --git a/src/include/final/final.h b/src/include/final/final.h index 06369f94..49d85d00 100644 --- a/src/include/final/final.h +++ b/src/include/final/final.h @@ -27,6 +27,7 @@ #define USE_FINAL_H #include +#include #include #include #include diff --git a/src/include/final/foptiattr.h b/src/include/final/foptiattr.h index 3df719c1..d4ffadde 100644 --- a/src/include/final/foptiattr.h +++ b/src/include/final/foptiattr.h @@ -23,9 +23,9 @@ /* Standalone class * ════════════════ * - * ▕▔▔▔▔▔▔▔▔▔▔▔▏ - * ▕ FOptiAttr ▏ - * ▕▁▁▁▁▁▁▁▁▁▁▁▏ + * ▕▔▔▔▔▔▔▔▔▔▔▔▏1 1▕▔▔▔▔▔▔▔▔▔▔▔▔▔▔▏ + * ▕ FOptiAttr ▏- - - -▕ SGRoptimizer ▏ + * ▕▁▁▁▁▁▁▁▁▁▁▁▏ ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▁▏ */ #ifndef FOPTIATTR_H @@ -59,6 +59,7 @@ #include // need for std::swap #include "final/fstring.h" +#include "final/sgr_optimizer.h" namespace finalcut { @@ -129,46 +130,46 @@ class FOptiAttr final const FString getClassName() const; // Mutators - void setTermEnvironment (termEnv&); - void setMaxColor (const int&); - void setNoColorVideo (int); - void setDefaultColorSupport(); - void unsetDefaultColorSupport(); - void set_enter_bold_mode (char[]); - void set_exit_bold_mode (char[]); - void set_enter_dim_mode (char[]); - void set_exit_dim_mode (char[]); - void set_enter_italics_mode (char[]); - void set_exit_italics_mode (char[]); - void set_enter_underline_mode (char[]); - void set_exit_underline_mode (char[]); - void set_enter_blink_mode (char[]); - void set_exit_blink_mode (char[]); - void set_enter_reverse_mode (char[]); - void set_exit_reverse_mode (char[]); - void set_enter_secure_mode (char[]); - void set_exit_secure_mode (char[]); - void set_enter_protected_mode (char[]); - void set_exit_protected_mode (char[]); - void set_enter_crossed_out_mode (char[]); - void set_exit_crossed_out_mode (char[]); - void set_enter_dbl_underline_mode (char[]); - void set_exit_dbl_underline_mode (char[]); - void set_enter_standout_mode (char[]); - void set_exit_standout_mode (char[]); - void set_set_attributes (char[]); - void set_exit_attribute_mode (char[]); - void set_enter_alt_charset_mode (char[]); - void set_exit_alt_charset_mode (char[]); - void set_enter_pc_charset_mode (char[]); - void set_exit_pc_charset_mode (char[]); - void set_a_foreground_color (char[]); - void set_a_background_color (char[]); - void set_foreground_color (char[]); - void set_background_color (char[]); - void set_term_color_pair (char[]); - void set_orig_pair (char[]); - void set_orig_orig_colors (char[]); + void setTermEnvironment (termEnv&); + void setMaxColor (const int&); + void setNoColorVideo (int); + void setDefaultColorSupport(); + void unsetDefaultColorSupport(); + void set_enter_bold_mode (char[]); + void set_exit_bold_mode (char[]); + void set_enter_dim_mode (char[]); + void set_exit_dim_mode (char[]); + void set_enter_italics_mode (char[]); + void set_exit_italics_mode (char[]); + void set_enter_underline_mode (char[]); + void set_exit_underline_mode (char[]); + void set_enter_blink_mode (char[]); + void set_exit_blink_mode (char[]); + void set_enter_reverse_mode (char[]); + void set_exit_reverse_mode (char[]); + void set_enter_secure_mode (char[]); + void set_exit_secure_mode (char[]); + void set_enter_protected_mode (char[]); + void set_exit_protected_mode (char[]); + void set_enter_crossed_out_mode (char[]); + void set_exit_crossed_out_mode (char[]); + void set_enter_dbl_underline_mode (char[]); + void set_exit_dbl_underline_mode (char[]); + void set_enter_standout_mode (char[]); + void set_exit_standout_mode (char[]); + void set_set_attributes (char[]); + void set_exit_attribute_mode (char[]); + void set_enter_alt_charset_mode (char[]); + void set_exit_alt_charset_mode (char[]); + void set_enter_pc_charset_mode (char[]); + void set_exit_pc_charset_mode (char[]); + void set_a_foreground_color (char[]); + void set_a_background_color (char[]); + void set_foreground_color (char[]); + void set_background_color (char[]); + void set_term_color_pair (char[]); + void set_orig_pair (char[]); + void set_orig_orig_colors (char[]); // Inquiry static bool isNormal (FChar*&); @@ -180,6 +181,8 @@ class FOptiAttr final private: // Typedefs and Enumerations + typedef char attributebuffer[SGRoptimizer::ATTR_BUF_SIZE]; + typedef struct { char* cap; @@ -219,115 +222,117 @@ class FOptiAttr final }; // Mutators - bool setTermBold (FChar*&); - bool unsetTermBold (FChar*&); - bool setTermDim (FChar*&); - bool unsetTermDim (FChar*&); - bool setTermItalic (FChar*&); - bool unsetTermItalic (FChar*&); - bool setTermUnderline (FChar*&); - bool unsetTermUnderline (FChar*&); - bool setTermBlink (FChar*&); - bool unsetTermBlink (FChar*&); - bool setTermReverse (FChar*&); - bool unsetTermReverse (FChar*&); - bool setTermStandout (FChar*&); - bool unsetTermStandout (FChar*&); - bool setTermInvisible (FChar*&); - bool unsetTermInvisible (FChar*&); - bool setTermProtected (FChar*&); - bool unsetTermProtected (FChar*&); - bool setTermCrossedOut (FChar*&); - bool unsetTermCrossedOut (FChar*&); - bool setTermDoubleUnderline (FChar*&); - bool unsetTermDoubleUnderline (FChar*&); - bool setTermAttributes ( FChar*& - , bool, bool, bool - , bool, bool, bool - , bool, bool, bool ); - bool unsetTermAttributes (FChar*&); - bool setTermAltCharset (FChar*&); - bool unsetTermAltCharset (FChar*&); - bool setTermPCcharset (FChar*&); - bool unsetTermPCcharset (FChar*&); - bool setTermDefaultColor (FChar*&); - void setAttributesOn (FChar*&); - void setAttributesOff (FChar*&); + bool setTermBold (FChar*&); + bool unsetTermBold (FChar*&); + bool setTermDim (FChar*&); + bool unsetTermDim (FChar*&); + bool setTermItalic (FChar*&); + bool unsetTermItalic (FChar*&); + bool setTermUnderline (FChar*&); + bool unsetTermUnderline (FChar*&); + bool setTermBlink (FChar*&); + bool unsetTermBlink (FChar*&); + bool setTermReverse (FChar*&); + bool unsetTermReverse (FChar*&); + bool setTermStandout (FChar*&); + bool unsetTermStandout (FChar*&); + bool setTermInvisible (FChar*&); + bool unsetTermInvisible (FChar*&); + bool setTermProtected (FChar*&); + bool unsetTermProtected (FChar*&); + bool setTermCrossedOut (FChar*&); + bool unsetTermCrossedOut (FChar*&); + bool setTermDoubleUnderline (FChar*&); + bool unsetTermDoubleUnderline (FChar*&); + bool setTermAttributes ( FChar*& + , bool, bool, bool + , bool, bool, bool + , bool, bool, bool ); + bool unsetTermAttributes (FChar*&); + bool setTermAltCharset (FChar*&); + bool unsetTermAltCharset (FChar*&); + bool setTermPCcharset (FChar*&); + bool unsetTermPCcharset (FChar*&); + bool setTermDefaultColor (FChar*&); + void setAttributesOn (FChar*&); + void setAttributesOff (FChar*&); // Inquiries - static bool hasColor (FChar*&); - static bool hasAttribute (FChar*&); - static bool hasNoAttribute (FChar*&); + static bool hasColor (FChar*&); + static bool hasAttribute (FChar*&); + static bool hasNoAttribute (FChar*&); // Methods - bool hasColorChanged (FChar*&, FChar*&); - void resetColor (FChar*&); - void prevent_no_color_video_attributes (FChar*&, bool = false); - void deactivateAttributes (FChar*&, FChar*&); - void changeAttributeSGR (FChar*&, FChar*&); - void changeAttributeSeparately (FChar*&, FChar*&); - void change_color (FChar*&, FChar*&); - void change_to_default_color (FChar*&, FChar*&, FColor&, FColor&); - void change_current_color (FChar*&, FColor, FColor); - void resetAttribute (FChar*&); - void reset (FChar*&); - bool caused_reset_attributes (char[], uChar = all_tests); - bool hasCharsetEquivalence(); - void detectSwitchOn (FChar*&, FChar*&); - void detectSwitchOff (FChar*&, FChar*&); - bool switchOn(); - bool switchOff(); - bool append_sequence (char[]); + bool hasColorChanged (FChar*&, FChar*&); + void resetColor (FChar*&); + void prevent_no_color_video_attributes (FChar*&, bool = false); + void deactivateAttributes (FChar*&, FChar*&); + void changeAttributeSGR (FChar*&, FChar*&); + void changeAttributeSeparately (FChar*&, FChar*&); + void change_color (FChar*&, FChar*&); + void change_to_default_color (FChar*&, FChar*&, FColor&, FColor&); + void change_current_color (FChar*&, FColor, FColor); + void resetAttribute (FChar*&); + void reset (FChar*&); + bool caused_reset_attributes (char[], uChar = all_tests); + bool hasCharsetEquivalence(); + void detectSwitchOn (FChar*&, FChar*&); + void detectSwitchOff (FChar*&, FChar*&); + bool switchOn(); + bool switchOff(); + bool append_sequence (char[]); // Data members - capability F_enter_bold_mode{}; - capability F_exit_bold_mode{}; - capability F_enter_dim_mode{}; - capability F_exit_dim_mode{}; - capability F_enter_italics_mode{}; - capability F_exit_italics_mode{}; - capability F_enter_underline_mode{}; - capability F_exit_underline_mode{}; - capability F_enter_blink_mode{}; - capability F_exit_blink_mode{}; - capability F_enter_reverse_mode{}; - capability F_exit_reverse_mode{}; - capability F_enter_standout_mode{}; - capability F_exit_standout_mode{}; - capability F_enter_secure_mode{}; - capability F_exit_secure_mode{}; - capability F_enter_protected_mode{}; - capability F_exit_protected_mode{}; - capability F_enter_crossed_out_mode{}; - capability F_exit_crossed_out_mode{}; - capability F_enter_dbl_underline_mode{}; - capability F_exit_dbl_underline_mode{}; - capability F_set_attributes{}; - capability F_exit_attribute_mode{}; - capability F_enter_alt_charset_mode{}; - capability F_exit_alt_charset_mode{}; - capability F_enter_pc_charset_mode{}; - capability F_exit_pc_charset_mode{}; - capability F_set_a_foreground{}; - capability F_set_a_background{}; - capability F_set_foreground{}; - capability F_set_background{}; - capability F_set_color_pair{}; - capability F_orig_pair{}; - capability F_orig_colors{}; + capability F_enter_bold_mode{}; + capability F_exit_bold_mode{}; + capability F_enter_dim_mode{}; + capability F_exit_dim_mode{}; + capability F_enter_italics_mode{}; + capability F_exit_italics_mode{}; + capability F_enter_underline_mode{}; + capability F_exit_underline_mode{}; + capability F_enter_blink_mode{}; + capability F_exit_blink_mode{}; + capability F_enter_reverse_mode{}; + capability F_exit_reverse_mode{}; + capability F_enter_standout_mode{}; + capability F_exit_standout_mode{}; + capability F_enter_secure_mode{}; + capability F_exit_secure_mode{}; + capability F_enter_protected_mode{}; + capability F_exit_protected_mode{}; + capability F_enter_crossed_out_mode{}; + capability F_exit_crossed_out_mode{}; + capability F_enter_dbl_underline_mode{}; + capability F_exit_dbl_underline_mode{}; + capability F_set_attributes{}; + capability F_exit_attribute_mode{}; + capability F_enter_alt_charset_mode{}; + capability F_exit_alt_charset_mode{}; + capability F_enter_pc_charset_mode{}; + capability F_exit_pc_charset_mode{}; + capability F_set_a_foreground{}; + capability F_set_a_background{}; + capability F_set_foreground{}; + capability F_set_background{}; + capability F_set_color_pair{}; + capability F_orig_pair{}; + capability F_orig_colors{}; - FChar on{}; - FChar off{}; - FChar reset_byte_mask{}; + FChar on{}; + FChar off{}; + FChar reset_byte_mask{}; - int max_color{1}; - int attr_without_color{0}; - char* attr_ptr{attr_buf}; - char attr_buf[8192]{'\0'}; - bool ansi_default_color{false}; - bool alt_equal_pc_charset{false}; - bool monochron{true}; - bool fake_reverse{false}; + SGRoptimizer sgr_optimizer{attr_buf}; + + int max_color{1}; + int attr_without_color{0}; + char* attr_ptr{attr_buf}; + char attr_buf[SGRoptimizer::ATTR_BUF_SIZE]{'\0'}; + bool ansi_default_color{false}; + bool alt_equal_pc_charset{false}; + bool monochron{true}; + bool fake_reverse{false}; }; diff --git a/src/include/final/fstartoptions.h b/src/include/final/fstartoptions.h index 9042eec8..06bcf7d7 100644 --- a/src/include/final/fstartoptions.h +++ b/src/include/final/fstartoptions.h @@ -78,9 +78,10 @@ class FStartOptions final uInt8 mouse_support : 1; uInt8 terminal_detection : 1; uInt8 color_change : 1; + uInt8 sgr_optimizer : 1; uInt8 vgafont : 1; uInt8 newfont : 1; - uInt8 : 2; // padding bits + uInt8 : 1; // padding bits fc::encoding encoding; #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(UNIT_TEST) diff --git a/src/include/final/sgr_optimizer.h b/src/include/final/sgr_optimizer.h new file mode 100644 index 00000000..b0c34a77 --- /dev/null +++ b/src/include/final/sgr_optimizer.h @@ -0,0 +1,93 @@ +/*********************************************************************** +* sgr_optimizer.h - Combines SGR (Select Graphic Rendition) attributes * +* * +* This file is part of the Final Cut widget toolkit * +* * +* Copyright 2019 Markus Gans * +* * +* The Final Cut is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public License * +* as published by the Free Software Foundation; either version 3 of * +* the License, or (at your option) any later version. * +* * +* The Final Cut is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with this program. If not, see * +* . * +***********************************************************************/ + +/* Standalone class + * ════════════════ + * + * ▕▔▔▔▔▔▔▔▔▔▔▔▔▔▔▏ + * ▕ SGRoptimizer ▏ + * ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▁▏ + */ + +#ifndef SGR_OPTIMIZER_H +#define SGR_OPTIMIZER_H + +#if !defined (USE_FINAL_H) && !defined (COMPILE_FINAL_CUT) + #error "Only can be included directly." +#endif + +#include + +namespace finalcut +{ + +//---------------------------------------------------------------------- +// class SGRoptimizer +//---------------------------------------------------------------------- + +class SGRoptimizer final +{ + public: + // Constants + static constexpr std::size_t ATTR_BUF_SIZE{8192}; + + // Typedefs + typedef char attributebuffer[ATTR_BUF_SIZE]; + + // Constructors + SGRoptimizer (attributebuffer&); + + // Destructor + virtual ~SGRoptimizer(); + + // Disable copy constructor + SGRoptimizer (const SGRoptimizer&) = delete; + + // Disable assignment operator (=) + SGRoptimizer& operator = (const SGRoptimizer&) = delete; + + // Method + void optimize(); + + private: + // Constants + static constexpr std::size_t NOT_SET = static_cast(-1); + + // Methods + void findParameter(); + void combineParameter(); + + // Data member + attributebuffer& seq; + + struct parameter + { + std::size_t start; + std::size_t end; + }; + + std::vector csi_parameter{}; +}; + +} // namespace finalcut + +#endif // SGR_OPTIMIZER_H diff --git a/src/sgr_optimizer.cpp b/src/sgr_optimizer.cpp new file mode 100644 index 00000000..7899ef33 --- /dev/null +++ b/src/sgr_optimizer.cpp @@ -0,0 +1,156 @@ +/*********************************************************************** +* sgr_optimizer.cpp - Combines SGR attributes * +* * +* This file is part of the Final Cut widget toolkit * +* * +* Copyright 2019 Markus Gans * +* * +* The Final Cut is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public License * +* as published by the Free Software Foundation; either version 3 of * +* the License, or (at your option) any later version. * +* * +* The Final Cut is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with this program. If not, see * +* . * +***********************************************************************/ + +#include + +#include "final/fc.h" +#include "final/sgr_optimizer.h" + +namespace finalcut +{ + +//---------------------------------------------------------------------- +// class SGRoptimizer +//---------------------------------------------------------------------- + +// constructors and destructor +//---------------------------------------------------------------------- +SGRoptimizer::SGRoptimizer (attributebuffer& sequence) + : seq(sequence) +{ } + +//---------------------------------------------------------------------- +SGRoptimizer::~SGRoptimizer() // destructor +{ } + + +// public methods of SGRoptimizer +//---------------------------------------------------------------------- +void SGRoptimizer::optimize() +{ + findParameter(); + combineParameter(); +} + + +// private methods of SGRoptimizer +//---------------------------------------------------------------------- +void SGRoptimizer::findParameter() +{ + // Find ANSI X3.64 terminal SGR (Select Graphic Rendition) strings + + std::size_t len = std::strlen(seq); + csi_parameter.clear(); + + if ( len < 6 ) + return; + + std::size_t start{NOT_SET}; + bool esc{false}, csi{false}; + + // Find SGR parameter + for (std::size_t i = 0; i < len; i++) + { + if ( csi == true ) + { + if ( start == NOT_SET ) + start = i; + + if ( (seq[i] >= '0' && seq[i] <= '9') || seq[i] == ';' ) + continue; + else if ( seq[i] == 'm') + { + csi_parameter.push_back({start, i}); + } + + esc = csi = false; + start = NOT_SET; + } + + if ( esc && seq[i] == '[' ) // Esc [ + csi = true; + + if ( seq[i] == ESC[0] ) // Esc + esc = true; + } +} + +//---------------------------------------------------------------------- +void SGRoptimizer::combineParameter() +{ + // Combine SGR (Select Graphic Rendition) attributes + + if ( csi_parameter.size() < 2 ) + return; + + const auto& first = csi_parameter.front(); + std::size_t count = 1; + std::size_t read_pos{}; + std::size_t write_pos = first.end; + + if ( first.start == first.end ) // Esc [ m + { + seq[write_pos] = '0'; + write_pos++; + } + + seq[write_pos] = ';'; + write_pos++; + const auto& begin = csi_parameter.cbegin() + 1; + const auto& end = csi_parameter.cend(); + + for (auto&& p : std::vector(begin, end)) + { + count++; + + for (read_pos = p.start; read_pos <= p.end; read_pos++) + { + if ( seq[read_pos] == 'm' ) + { + if ( p.start == p.end ) // Esc [ m + { + seq[write_pos] = '0'; + write_pos++; + } + + if ( count == csi_parameter.size() ) + seq[write_pos] = 'm'; + else + seq[write_pos] = ';'; + } + else + seq[write_pos] = seq[read_pos]; + + write_pos++; + } + } + + while ( seq[write_pos] != '\0' ) + { + seq[write_pos] = seq[read_pos]; + read_pos++; + write_pos++; + } +} + +} // namespace finalcut + diff --git a/test/foptiattr-test.cpp b/test/foptiattr-test.cpp index e59dbf1f..a04e9901 100644 --- a/test/foptiattr-test.cpp +++ b/test/foptiattr-test.cpp @@ -68,6 +68,7 @@ class FOptiAttrTest : public CPPUNIT_NS::TestFixture void classNameTest(); void noArgumentTest(); void vga2ansiTest(); + void sgrOptimizerTest(); void fakeReverseTest(); void ansiTest(); void vt100Test(); @@ -90,6 +91,7 @@ class FOptiAttrTest : public CPPUNIT_NS::TestFixture CPPUNIT_TEST (classNameTest); CPPUNIT_TEST (noArgumentTest); CPPUNIT_TEST (vga2ansiTest); + CPPUNIT_TEST (sgrOptimizerTest); CPPUNIT_TEST (fakeReverseTest); CPPUNIT_TEST (ansiTest); CPPUNIT_TEST (vt100Test); @@ -138,6 +140,149 @@ void FOptiAttrTest::noArgumentTest() delete ch; } +//---------------------------------------------------------------------- +void FOptiAttrTest::sgrOptimizerTest() +{ + // Test with FOptiAttr + // ------------------- + finalcut::FStartOptions::getFStartOptions().sgr_optimizer = true; + finalcut::FOptiAttr oa; + oa.setDefaultColorSupport(); // ANSI default color + oa.setMaxColor (8); + oa.setNoColorVideo (3); // Avoid standout (1) + underline mode (2) + oa.set_enter_bold_mode (C_STR(CSI "1m")); + oa.set_exit_bold_mode (C_STR(CSI "22m")); + oa.set_enter_dim_mode (C_STR(CSI "2m")); + oa.set_exit_dim_mode (C_STR(CSI "22m")); + oa.set_enter_italics_mode (C_STR(CSI "3m")); + oa.set_exit_italics_mode (C_STR(CSI "23m")); + oa.set_enter_underline_mode (0); + oa.set_exit_underline_mode (0); + oa.set_enter_blink_mode (C_STR(CSI "5m")); + oa.set_exit_blink_mode (C_STR(CSI "25m")); + oa.set_enter_reverse_mode (C_STR(CSI "7m")); + oa.set_exit_reverse_mode (C_STR(CSI "27m")); + oa.set_enter_standout_mode (0); + oa.set_exit_standout_mode (0); + oa.set_enter_secure_mode (C_STR(CSI "8m")); + oa.set_exit_secure_mode (C_STR(CSI "28m")); + oa.set_enter_protected_mode (0); + oa.set_exit_protected_mode (C_STR(CSI "0m")); + oa.set_enter_crossed_out_mode (C_STR(CSI "9m")); + oa.set_exit_crossed_out_mode (C_STR(CSI "29m")); + oa.set_enter_dbl_underline_mode (C_STR(CSI "21m")); + oa.set_exit_dbl_underline_mode (C_STR(CSI "24m")); + oa.set_set_attributes (C_STR(CSI "0;10" + "%?%p3%t;7%;" + "%?%p4%t;5%;" + "%?%p5%t;2%;" + "%?%p6%t;1%;" + "%?%p7%t;8%;" + "%?%p9%t;11%;m")); + oa.set_exit_attribute_mode (C_STR(CSI "0m")); + oa.set_enter_alt_charset_mode (C_STR(CSI "11m")); + oa.set_exit_alt_charset_mode (C_STR(CSI "10m")); + oa.set_enter_pc_charset_mode (C_STR(CSI "11m")); + oa.set_exit_pc_charset_mode (C_STR(CSI "10m")); + oa.set_a_foreground_color (C_STR(CSI "3%p1%dm")); + oa.set_a_background_color (C_STR(CSI "4%p1%dm")); + oa.set_foreground_color (0); + oa.set_background_color (0); + oa.set_term_color_pair (0); + oa.set_orig_pair (C_STR(CSI "39;49m")); + oa.set_orig_orig_colors (0); + oa.initialize(); + + finalcut::FChar* from = new finalcut::FChar(); + finalcut::FChar* to = new finalcut::FChar(); + CPPUNIT_ASSERT ( oa.changeAttribute(from, to) == 0 ); + + // Blue text on white background + bold + dim + italic + to->fg_color = finalcut::fc::Blue; + to->bg_color = finalcut::fc::White; + to->attr.bit.bold = true; + to->attr.bit.dim = true; + to->attr.bit.italic = true; + CPPUNIT_ASSERT ( *from != *to ); + CPPUNIT_ASSERT_CSTRING ( oa.changeAttribute(from, to) + , C_STR(CSI "0;10;2;1;3;34;47m") ); + CPPUNIT_ASSERT ( *from == *to ); + CPPUNIT_ASSERT ( oa.changeAttribute(from, to) == 0 ); + + // Yellow text on Black Yellow + bold + to->fg_color = finalcut::fc::Yellow; + to->bg_color = finalcut::fc::Black; + to->attr.bit.bold = true; + to->attr.bit.dim = false; + to->attr.bit.italic = false; + CPPUNIT_ASSERT ( *from != *to ); + CPPUNIT_ASSERT_CSTRING ( oa.changeAttribute(from, to) + , C_STR(CSI "0;10;1;33;40m") ); + CPPUNIT_ASSERT ( *from == *to ); + CPPUNIT_ASSERT ( oa.changeAttribute(from, to) == 0 ); + + + // Test only the optimizer + // ----------------------- + char buffer[8192] = { CSI "0;10m" CSI "11m" CSI "36m" CSI "44m" }; + finalcut::SGRoptimizer sgr_optimizer(buffer); + sgr_optimizer.optimize(); + CPPUNIT_ASSERT_CSTRING ( buffer, C_STR(CSI "0;10;11;36;44m") ); + + std::strcpy(buffer, CSI "0;1m" CSI "34m"); + sgr_optimizer.optimize(); + CPPUNIT_ASSERT_CSTRING ( buffer, C_STR(CSI "0;1;34m") ); + + std::strcpy(buffer, CSI "m" CSI "34m"); + sgr_optimizer.optimize(); + CPPUNIT_ASSERT_CSTRING ( buffer, C_STR(CSI "0;34m") ); + + std::strcpy(buffer, CSI "1m" CSI "m" CSI "45m"); + sgr_optimizer.optimize(); + CPPUNIT_ASSERT_CSTRING ( buffer, C_STR(CSI "1;0;45m") ); + + std::strcpy(buffer, CSI "47m"); + sgr_optimizer.optimize(); + CPPUNIT_ASSERT_CSTRING ( buffer, C_STR(CSI "47m") ); + + std::strcpy(buffer, CSI "47m" CSI "m" CSI "1m"); + sgr_optimizer.optimize(); + CPPUNIT_ASSERT_CSTRING ( buffer, C_STR(CSI "47;0;1m") ); + + std::strcpy(buffer, CSI "49m" CSI "m" CSI "0m"); + sgr_optimizer.optimize(); + CPPUNIT_ASSERT_CSTRING ( buffer, C_STR(CSI "49;0;0m") ); + + std::strcpy(buffer, CSI "m" CSI "m" CSI "m"); + sgr_optimizer.optimize(); + CPPUNIT_ASSERT_CSTRING ( buffer, C_STR(CSI "0;0;0m") ); + + std::strcpy(buffer, CSI "m"); + sgr_optimizer.optimize(); + CPPUNIT_ASSERT_CSTRING ( buffer, C_STR(CSI "m") ); + + std::strcpy(buffer, CSI "0;10;1;7m" CSI "3m" CSI "39m" CSI "49m"); + sgr_optimizer.optimize(); + CPPUNIT_ASSERT_CSTRING ( buffer, C_STR(CSI "0;10;1;7;3;39;49m") ); + + std::strcpy(buffer, CSI "m" CSI "38;5;20m" CSI "48;5;229m"); + sgr_optimizer.optimize(); + CPPUNIT_ASSERT_CSTRING ( buffer, C_STR(CSI "0;38;5;20;48;5;229m") ); + + std::strcpy(buffer, CSI "m" CSI "1m" CSI "2m" CSI "3m" CSI "4m" + CSI "5m" CSI "7m" CSI "8m" CSI "9m"); + sgr_optimizer.optimize(); + CPPUNIT_ASSERT_CSTRING ( buffer, C_STR(CSI "0;1;2;3;4;5;7;8;9m") ); + + std::strcpy(buffer, CSI "0m" CSI "46;36;1m"); + sgr_optimizer.optimize(); + CPPUNIT_ASSERT_CSTRING ( buffer, C_STR(CSI "0;46;36;1m") ); + + std::strcpy(buffer, CSI "m" CSI "38;2;0;139;139m" CSI "48;2;240;255;240m"); + sgr_optimizer.optimize(); + CPPUNIT_ASSERT_CSTRING ( buffer, C_STR(CSI "0;38;2;0;139;139;48;2;240;255;240m") ); +} + //---------------------------------------------------------------------- void FOptiAttrTest::vga2ansiTest() { @@ -163,6 +308,7 @@ void FOptiAttrTest::vga2ansiTest() //---------------------------------------------------------------------- void FOptiAttrTest::fakeReverseTest() { + finalcut::FStartOptions::getFStartOptions().sgr_optimizer = false; finalcut::FOptiAttr oa; oa.setDefaultColorSupport(); // ANSI default color oa.setMaxColor (8); @@ -251,6 +397,7 @@ void FOptiAttrTest::ansiTest() { // Simulate an ansi terminal + finalcut::FStartOptions::getFStartOptions().sgr_optimizer = false; finalcut::FOptiAttr oa; oa.setDefaultColorSupport(); // ANSI default color oa.setMaxColor (8); @@ -718,6 +865,7 @@ void FOptiAttrTest::vt100Test() { // Simulate a vt100 terminal + finalcut::FStartOptions::getFStartOptions().sgr_optimizer = false; finalcut::FOptiAttr oa; oa.unsetDefaultColorSupport(); // No ANSI default color oa.setMaxColor (1); @@ -1179,6 +1327,7 @@ void FOptiAttrTest::xtermTest() { // Simulate an xterm-256color terminal + finalcut::FStartOptions::getFStartOptions().sgr_optimizer = false; finalcut::FOptiAttr oa; oa.setDefaultColorSupport(); // ANSI default color oa.setMaxColor (256); @@ -1660,6 +1809,7 @@ void FOptiAttrTest::rxvtTest() { // Simulate an rxvt terminal + finalcut::FStartOptions::getFStartOptions().sgr_optimizer = false; finalcut::FOptiAttr oa; oa.setDefaultColorSupport(); // ANSI default color oa.setMaxColor (8); @@ -2131,6 +2281,7 @@ void FOptiAttrTest::linuxTest() { // Simulate a Linux terminal with 16 colors + finalcut::FStartOptions::getFStartOptions().sgr_optimizer = false; finalcut::FOptiAttr oa; oa.setDefaultColorSupport(); // ANSI default color oa.setMaxColor (16); @@ -2605,6 +2756,7 @@ void FOptiAttrTest::puttyTest() { // Simulate a putty-256color terminal + finalcut::FStartOptions::getFStartOptions().sgr_optimizer = false; finalcut::FOptiAttr oa; oa.unsetDefaultColorSupport(); // No ANSI default color oa.setMaxColor (256); @@ -3087,6 +3239,7 @@ void FOptiAttrTest::teratermTest() { // Simulate a Tera Term terminal + finalcut::FStartOptions::getFStartOptions().sgr_optimizer = false; finalcut::FOptiAttr oa; oa.unsetDefaultColorSupport(); // No ANSI default color oa.setMaxColor (16); @@ -3553,6 +3706,7 @@ void FOptiAttrTest::ibmColorTest() { // Simulate IBM color definitions + finalcut::FStartOptions::getFStartOptions().sgr_optimizer = false; finalcut::FOptiAttr oa; oa.unsetDefaultColorSupport(); // No ANSI default color oa.setMaxColor (8); @@ -3991,6 +4145,7 @@ void FOptiAttrTest::wyse50Test() { // Simulate an Wyse-50 terminal + finalcut::FStartOptions::getFStartOptions().sgr_optimizer = false; finalcut::FOptiAttr oa; finalcut::FOptiAttr::termEnv optiattr_env = {