finalcut/src/fterm.cpp

2776 lines
66 KiB
C++
Raw Normal View History

2017-11-04 07:03:53 +01:00
/***********************************************************************
* fterm.cpp - Base class for terminal control *
2017-11-04 07:03:53 +01:00
* *
* This file is part of the Final Cut widget toolkit *
* *
* Copyright 2012-2019 Markus Gans *
2017-11-04 07:03:53 +01:00
* *
* 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 *
* <http://www.gnu.org/licenses/>. *
***********************************************************************/
2015-05-23 13:35:12 +02:00
2017-09-11 03:06:02 +02:00
#include <algorithm>
#include <unordered_map>
2017-09-11 03:06:02 +02:00
#include <string>
#include <vector>
#include "final/fc.h"
#include "final/fcharmap.h"
#include "final/fcolorpalette.h"
#include "final/fkey_map.h"
#include "final/fkeyboard.h"
#include "final/fmouse.h"
#include "final/foptiattr.h"
#include "final/foptimove.h"
#include "final/fstartoptions.h"
#include "final/fstring.h"
#include "final/fsystemimpl.h"
#include "final/fterm.h"
#include "final/ftermbuffer.h"
#include "final/ftermcap.h"
#include "final/ftermcapquirks.h"
#include "final/ftermdata.h"
#include "final/ftermdebugdata.h"
#include "final/ftermdetection.h"
#include "final/ftermios.h"
#include "final/ftermxterminal.h"
#if defined(UNIT_TEST)
#include "final/ftermlinux.h"
#include "final/ftermfreebsd.h"
#include "final/ftermopenbsd.h"
#elif defined(__linux__)
#include "final/ftermlinux.h"
#elif defined(__FreeBSD__) || defined(__DragonFly__)
#include "final/ftermfreebsd.h"
#elif defined(__NetBSD__) || defined(__OpenBSD__)
#include "final/ftermopenbsd.h"
#endif
2015-05-23 13:35:12 +02:00
namespace finalcut
{
2015-05-23 13:35:12 +02:00
// global FTerm object
2019-08-25 22:16:00 +02:00
static FTerm* init_term_object{nullptr};
2015-05-23 13:35:12 +02:00
// global init state
2019-08-25 22:16:00 +02:00
static bool term_initialized{false};
2015-05-23 13:35:12 +02:00
// function pointer
int (*FTerm::Fputchar)(int);
// static class attributes
2019-08-25 22:16:00 +02:00
FTermData* FTerm::data {nullptr};
FSystem* FTerm::fsys {nullptr};
FOptiMove* FTerm::opti_move {nullptr};
FOptiAttr* FTerm::opti_attr {nullptr};
FTermDetection* FTerm::term_detection{nullptr};
FTermXTerminal* FTerm::xterm {nullptr};
FKeyboard* FTerm::keyboard {nullptr};
FMouseControl* FTerm::mouse {nullptr};
2015-05-23 13:35:12 +02:00
2019-07-14 18:30:35 +02:00
#if defined(UNIT_TEST)
2019-08-25 22:16:00 +02:00
FTermLinux* FTerm::linux {nullptr};
FTermFreeBSD* FTerm::freebsd {nullptr};
FTermOpenBSD* FTerm::openbsd {nullptr};
2019-07-14 18:30:35 +02:00
#elif defined(__linux__)
2019-08-25 22:16:00 +02:00
FTermLinux* FTerm::linux {nullptr};
2018-10-08 04:14:20 +02:00
#elif defined(__FreeBSD__) || defined(__DragonFly__)
2019-08-25 22:16:00 +02:00
FTermFreeBSD* FTerm::freebsd {nullptr};
2018-10-08 04:14:20 +02:00
#elif defined(__NetBSD__) || defined(__OpenBSD__)
2019-08-25 22:16:00 +02:00
FTermOpenBSD* FTerm::openbsd {nullptr};
#endif
#if DEBUG
2019-08-25 22:16:00 +02:00
FTermDebugData* FTerm::debug_data {nullptr};
#endif
// function prototypes
uInt env2uint (const char*);
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
// class FTerm
//----------------------------------------------------------------------
// constructors and destructor
//----------------------------------------------------------------------
2017-03-26 20:40:04 +02:00
FTerm::FTerm (bool disable_alt_screen)
2015-05-23 13:35:12 +02:00
{
if ( ! term_initialized )
init (disable_alt_screen);
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
FTerm::~FTerm() // destructor
{
if ( init_term_object == this )
finish(); // Resetting console settings
2015-05-23 13:35:12 +02:00
}
// public methods of FTerm
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
std::size_t FTerm::getLineNumber()
2015-05-23 13:35:12 +02:00
{
auto& term_geometry = data->getTermGeometry();
if ( term_geometry.getHeight() == 0 )
detectTermSize();
return term_geometry.getHeight();
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
std::size_t FTerm::getColumnNumber()
2015-05-23 13:35:12 +02:00
{
auto& term_geometry = data->getTermGeometry();
if ( term_geometry.getWidth() == 0 )
detectTermSize();
return term_geometry.getWidth();
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
2018-11-21 20:07:08 +01:00
const FString FTerm::getKeyName (FKey keynum)
{
return keyboard->getKeyName (keynum);
}
//----------------------------------------------------------------------
charSubstitution& FTerm::getCharSubstitutionMap()
{
return data->getCharSubstitutionMap();
}
//----------------------------------------------------------------------
int FTerm::getTTYFileDescriptor()
{
return ( data ) ? data->getTTYFileDescriptor() : 0;
}
//----------------------------------------------------------------------
char* FTerm::getTermType()
{
return data->getTermType();
}
//----------------------------------------------------------------------
char* FTerm::getTermFileName()
{
return data->getTermFileName();
}
//----------------------------------------------------------------------
int FTerm::getTabstop()
{
return FTermcap::tabstop;
}
//----------------------------------------------------------------------
int FTerm::getMaxColor()
{
return FTermcap::max_color;
}
//----------------------------------------------------------------------
FTermData* FTerm::getFTermData()
{
if ( data == 0 )
{
try
{
data = new FTermData;
}
catch (const std::bad_alloc& ex)
{
std::cerr << bad_alloc_str << ex.what() << std::endl;
std::abort();
}
}
return data;
}
//----------------------------------------------------------------------
FSystem* FTerm::getFSystem()
{
if ( fsys == 0 )
{
try
{
fsys = new FSystemImpl;
}
catch (const std::bad_alloc& ex)
{
std::cerr << bad_alloc_str << ex.what() << std::endl;
std::abort();
}
}
return fsys;
}
//----------------------------------------------------------------------
FOptiMove* FTerm::getFOptiMove()
{
if ( opti_move == 0 )
{
try
{
opti_move = new FOptiMove;
}
catch (const std::bad_alloc& ex)
{
std::cerr << bad_alloc_str << ex.what() << std::endl;
std::abort();
}
}
return opti_move;
}
//----------------------------------------------------------------------
FOptiAttr* FTerm::getFOptiAttr()
{
if ( opti_attr == 0 )
{
try
{
opti_attr = new FOptiAttr;
}
catch (const std::bad_alloc& ex)
{
std::cerr << bad_alloc_str << ex.what() << std::endl;
std::abort();
}
}
return opti_attr;
}
//----------------------------------------------------------------------
FTermDetection* FTerm::getFTermDetection()
{
if ( term_detection == 0 )
{
try
{
term_detection = new FTermDetection;
}
catch (const std::bad_alloc& ex)
{
std::cerr << bad_alloc_str << ex.what() << std::endl;
std::abort();
}
}
return term_detection;
}
//----------------------------------------------------------------------
FTermXTerminal* FTerm::getFTermXTerminal()
{
if ( xterm == 0 )
{
try
{
xterm = new FTermXTerminal;
}
catch (const std::bad_alloc& ex)
{
std::cerr << bad_alloc_str << ex.what() << std::endl;
std::abort();
}
}
return xterm;
}
//----------------------------------------------------------------------
FKeyboard* FTerm::getFKeyboard()
{
if ( keyboard == 0 )
{
try
{
keyboard = new FKeyboard;
}
catch (const std::bad_alloc& ex)
{
std::cerr << bad_alloc_str << ex.what() << std::endl;
std::abort();
}
}
return keyboard;
}
//----------------------------------------------------------------------
FMouseControl* FTerm::getFMouseControl()
{
if ( mouse == 0 )
{
try
{
mouse = new FMouseControl;
}
catch (const std::bad_alloc& ex)
{
std::cerr << bad_alloc_str << ex.what() << std::endl;
std::abort();
}
}
return mouse;
}
#if defined(__linux__)
//----------------------------------------------------------------------
FTermLinux* FTerm::getFTermLinux()
{
if ( linux == 0 )
{
try
{
linux = new FTermLinux;
}
catch (const std::bad_alloc& ex)
{
std::cerr << bad_alloc_str << ex.what() << std::endl;
std::abort();
}
}
return linux;
}
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(UNIT_TEST)
//----------------------------------------------------------------------
FTermFreeBSD* FTerm::getFTermFreeBSD()
{
if ( freebsd == 0 )
{
try
{
freebsd = new FTermFreeBSD;
}
catch (const std::bad_alloc& ex)
{
std::cerr << bad_alloc_str << ex.what() << std::endl;
std::abort();
}
}
return freebsd;
}
#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(UNIT_TEST)
//----------------------------------------------------------------------
FTermOpenBSD* FTerm::getFTermOpenBSD()
{
if ( openbsd == 0 )
{
try
{
openbsd = new FTermOpenBSD;
}
catch (const std::bad_alloc& ex)
{
std::cerr << bad_alloc_str << ex.what() << std::endl;
std::abort();
}
}
return openbsd;
}
#endif
#if DEBUG
//----------------------------------------------------------------------
FTermDebugData& FTerm::getFTermDebugData()
{
if ( debug_data == 0 )
{
try
{
debug_data = new FTermDebugData;
}
catch (const std::bad_alloc& ex)
{
std::cerr << bad_alloc_str << ex.what() << std::endl;
std::abort();
}
}
return *debug_data;
}
#endif // DEBUG
2016-11-26 15:18:44 +01:00
//----------------------------------------------------------------------
bool FTerm::isNormal (charData*& ch)
2016-11-26 15:18:44 +01:00
{
return opti_attr->isNormal(ch);
}
//----------------------------------------------------------------------
bool FTerm::hasUTF8()
{
return data->hasUTF8Console();
}
//----------------------------------------------------------------------
bool FTerm::isMonochron()
{
return data->isMonochron();
}
//----------------------------------------------------------------------
bool FTerm::isXTerminal()
{
return term_detection->isXTerminal();
}
//----------------------------------------------------------------------
bool FTerm::isAnsiTerminal()
{
return term_detection->isAnsiTerminal();
}
//----------------------------------------------------------------------
bool FTerm::isRxvtTerminal()
{
return term_detection->isRxvtTerminal();
}
//----------------------------------------------------------------------
bool FTerm::isUrxvtTerminal()
{
return term_detection->isUrxvtTerminal();
}
//----------------------------------------------------------------------
bool FTerm::isMltermTerminal()
{
return term_detection->isMltermTerminal();
}
//----------------------------------------------------------------------
bool FTerm::isPuttyTerminal()
{
return term_detection->isPuttyTerminal();
}
//----------------------------------------------------------------------
bool FTerm::isKdeTerminal()
{
return term_detection->isKdeTerminal();
}
//----------------------------------------------------------------------
bool FTerm::isGnomeTerminal()
{
return term_detection->isGnomeTerminal();
}
//----------------------------------------------------------------------
bool FTerm::isKtermTerminal()
{
return term_detection->isKtermTerminal();
}
//----------------------------------------------------------------------
bool FTerm::isTeraTerm()
{
return term_detection->isTeraTerm();
}
//----------------------------------------------------------------------
bool FTerm::isSunTerminal()
{
return term_detection->isSunTerminal();
}
//----------------------------------------------------------------------
bool FTerm::isCygwinTerminal()
{
return term_detection->isCygwinTerminal();
}
//----------------------------------------------------------------------
bool FTerm::isMinttyTerm()
{
return term_detection->isMinttyTerm();
}
//----------------------------------------------------------------------
bool FTerm::isLinuxTerm()
{
return term_detection->isLinuxTerm();
}
//----------------------------------------------------------------------
bool FTerm::isFreeBSDTerm()
{
return term_detection->isFreeBSDTerm();
}
//----------------------------------------------------------------------
bool FTerm::isNetBSDTerm()
{
return term_detection->isNetBSDTerm();
}
//----------------------------------------------------------------------
bool FTerm::isOpenBSDTerm()
{
return term_detection->isOpenBSDTerm();
}
//----------------------------------------------------------------------
bool FTerm::isScreenTerm()
{
return term_detection->isScreenTerm();
}
//----------------------------------------------------------------------
bool FTerm::isTmuxTerm()
{
return term_detection->isTmuxTerm();
}
//----------------------------------------------------------------------
bool FTerm::isNewFont()
{
return data->isNewFont();
}
//----------------------------------------------------------------------
2018-10-29 00:45:45 +01:00
bool FTerm::isCursorHideable()
{
const char* cursor_off_str = disableCursorString();
2018-10-29 00:45:45 +01:00
if ( cursor_off_str && std::strlen(cursor_off_str) > 0 )
return true;
return false;
}
//----------------------------------------------------------------------
bool FTerm::hasChangedTermSize()
{
return data->hasTermResized();
}
//----------------------------------------------------------------------
bool FTerm::hasShadowCharacter()
{
return data->hasShadowCharacter();
}
//----------------------------------------------------------------------
bool FTerm::hasHalfBlockCharacter()
{
return data->hasHalfBlockCharacter();
}
//----------------------------------------------------------------------
bool FTerm::hasAlternateScreen()
{
return data->hasAlternateScreen();
}
//----------------------------------------------------------------------
bool FTerm::canChangeColorPalette()
{
if ( isCygwinTerminal()
|| isKdeTerminal()
|| isTeraTerm()
|| isMltermTerminal()
|| isNetBSDTerm()
|| isOpenBSDTerm()
|| isSunTerminal()
|| isAnsiTerminal() )
return false;
return FTermcap::can_change_color_palette;
}
2018-10-29 00:45:45 +01:00
//----------------------------------------------------------------------
2018-08-09 00:04:00 +02:00
void FTerm::setTermType (const char term_name[])
{
data->setTermType(term_name);
}
//----------------------------------------------------------------------
2018-12-22 23:50:10 +01:00
void FTerm::setInsertCursor (bool enable)
{
2018-12-22 23:50:10 +01:00
if ( enable )
setInsertCursorStyle();
else
setOverwriteCursorStyle();
}
//----------------------------------------------------------------------
2018-12-22 23:50:10 +01:00
void FTerm::redefineDefaultColors (bool enable)
{
if ( isNewFont() ) // NewFont need the reverse-video attribute
return;
2018-12-22 23:50:10 +01:00
xterm->redefineDefaultColors (enable);
}
2018-01-16 16:16:29 +01:00
//----------------------------------------------------------------------
2018-12-28 22:57:43 +01:00
void FTerm::setDblclickInterval (const uInt64 timeout)
2018-01-16 16:16:29 +01:00
{
mouse->setDblclickInterval(timeout);
}
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
2018-12-22 23:50:10 +01:00
bool FTerm::setUTF8 (bool enable) // UTF-8 (Unicode)
2015-05-23 13:35:12 +02:00
{
2018-12-22 23:50:10 +01:00
if ( data->isUTF8() == enable )
return enable;
2015-05-23 13:35:12 +02:00
2018-12-22 23:50:10 +01:00
if ( enable )
data->setUTF8(true);
else
data->setUTF8(false);
#if defined(__linux__)
2018-12-22 23:50:10 +01:00
linux->setUTF8 (enable);
#endif
return data->isUTF8();
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
bool FTerm::setVGAFont()
{
if ( data->isVGAFont() )
return data->isVGAFont();
2015-05-23 13:35:12 +02:00
2018-10-09 00:33:26 +02:00
if ( hasNoFontSettingOption() )
return false;
2015-05-23 13:35:12 +02:00
if ( isXTerminal() || isScreenTerm()
|| isUrxvtTerminal() || FTermcap::osc_support )
2015-05-23 13:35:12 +02:00
{
data->setVGAFont(true);
// Set font in xterm to vga
xterm->setFont("vga");
data->setNewFont(false);
data->setTermEncoding (fc::PC);
if ( isXTerminal() && data->hasUTF8Console() )
Fputchar = &FTerm::putchar_UTF8;
else
Fputchar = &FTerm::putchar_ASCII;
}
2017-03-26 20:40:04 +02:00
#if defined(__linux__)
else if ( isLinuxTerm() )
{
data->setVGAFont(linux->loadVGAFont());
data->setTermEncoding (fc::PC);
Fputchar = &FTerm::putchar_ASCII;
2015-05-23 13:35:12 +02:00
}
#endif // defined(__linux__)
else
data->setVGAFont(false);
if ( data->isVGAFont() )
{
data->supportShadowCharacter (true);
data->supportHalfBlockCharacter (true);
}
return data->isVGAFont();
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
bool FTerm::setNewFont()
2015-05-23 13:35:12 +02:00
{
if ( isNewFont() )
return true;
2015-05-23 13:35:12 +02:00
2018-10-09 00:33:26 +02:00
if ( hasNoFontSettingOption() )
return false;
2015-05-23 13:35:12 +02:00
if ( isXTerminal() || isScreenTerm()
|| isUrxvtTerminal() || FTermcap::osc_support )
2015-05-23 13:35:12 +02:00
{
data->setNewFont(true);
// Set font in xterm to 8x16graph
xterm->setFont("8x16graph");
data->setTermEncoding (fc::PC);
if ( isXTerminal() && data->hasUTF8Console() )
Fputchar = &FTerm::putchar_UTF8;
else
Fputchar = &FTerm::putchar_ASCII;
}
2017-03-26 20:40:04 +02:00
#if defined(__linux__)
else if ( isLinuxTerm() )
{
data->setNewFont(linux->loadNewFont());
data->setTermEncoding (fc::PC);
Fputchar = &FTerm::putchar_ASCII; // function pointer
2015-05-23 13:35:12 +02:00
}
#endif // defined(__linux__)
else
data->setNewFont(false);
if ( isNewFont() )
{
data->supportShadowCharacter (true);
data->supportHalfBlockCharacter (true);
}
return isNewFont();
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
bool FTerm::setOldFont()
2015-05-23 13:35:12 +02:00
{
2019-08-25 22:16:00 +02:00
bool retval{false};
if ( ! (data->isNewFont() || data->isVGAFont()) )
return false;
data->setNewFont(false);
data->setVGAFont(false);
2015-05-23 13:35:12 +02:00
if ( isXTerminal() || isScreenTerm()
|| isUrxvtTerminal() || FTermcap::osc_support )
{
2018-12-26 23:41:49 +01:00
const auto& font = data->getXtermFont();
if ( font.getLength() > 2 )
2015-05-23 13:35:12 +02:00
{
// restore saved xterm font
xterm->setFont (font);
2015-05-23 13:35:12 +02:00
}
else
2015-05-23 13:35:12 +02:00
{
// Set font in xterm to vga
xterm->setFont("vga");
}
retval = true;
}
2017-03-26 20:40:04 +02:00
#if defined(__linux__)
else if ( isLinuxTerm() )
{
retval = linux->loadOldFont();
2015-05-23 13:35:12 +02:00
}
#endif // defined(__linux__)
if ( retval )
{
data->setVGAFont(false);
data->setNewFont(false);
}
return retval;
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
int FTerm::openConsole()
{
if ( ! data )
data = FTerm::getFTermData();
int fd = data->getTTYFileDescriptor();
const char* termfilename = data->getTermFileName();
static const char* terminal_devices[] =
{
"/proc/self/fd/0",
"/dev/tty",
"/dev/tty0",
"/dev/vc/0",
"/dev/systty",
"/dev/console",
0
};
if ( fd >= 0 ) // console is already opened
return 0;
if ( ! *termfilename || ! fsys )
return 0;
2019-08-25 22:16:00 +02:00
for (std::size_t i{0}; terminal_devices[i] != 0; i++)
{
fd = fsys->open(terminal_devices[i], O_RDWR, 0);
data->setTTYFileDescriptor(fd);
if ( fd >= 0 )
return 0;
}
return -1; // No file descriptor referring to the console
}
//----------------------------------------------------------------------
int FTerm::closeConsole()
{
if ( ! data )
data = FTerm::getFTermData();
int fd = data->getTTYFileDescriptor();
2019-08-25 22:16:00 +02:00
int ret{-1};
if ( fd < 0 ) // console is already closed
return 0;
2019-09-29 22:28:58 +02:00
if ( ! fsys )
getFSystem();
ret = fsys->close(fd); // close console
data->setTTYFileDescriptor(-1);
if ( ret == 0 )
return 0;
else
return -1;
}
//----------------------------------------------------------------------
char* FTerm::moveCursorString (int xold, int yold, int xnew, int ynew)
{
// Returns the cursor move string
if ( data->hasCursorOptimisation() )
return opti_move->moveCursor (xold, yold, xnew, ynew);
else
2017-09-11 03:06:02 +02:00
return tgoto(TCAP(fc::t_cursor_address), xnew, ynew);
}
//----------------------------------------------------------------------
char* FTerm::cursorsVisibilityString (bool enable)
{
// Hides or shows the input cursor on the terminal
2019-08-25 22:16:00 +02:00
char* visibility_str{nullptr};
2018-12-22 23:50:10 +01:00
if ( data->isCursorHidden() == enable )
return 0;
2018-12-22 23:50:10 +01:00
if ( enable )
{
visibility_str = disableCursorString();
if ( visibility_str )
data->setCursorHidden (true); // Global state
}
else
{
visibility_str = enableCursorString();
if ( visibility_str )
data->setCursorHidden (false); // Global state
}
return visibility_str;
}
//----------------------------------------------------------------------
void FTerm::detectTermSize()
{
// Detect the terminal width and height
if ( ! data )
data = FTerm::getFTermData();
2019-08-25 22:16:00 +02:00
struct winsize win_size{};
auto& term_geometry = data->getTermGeometry();
2019-08-25 22:16:00 +02:00
int ret{};
errno = 0;
do
{
2019-09-29 22:28:58 +02:00
if ( ! fsys )
getFSystem();
ret = fsys->ioctl (FTermios::getStdOut(), TIOCGWINSZ, &win_size);
}
while (errno == EINTR);
2015-10-07 02:36:38 +02:00
if ( ret != 0 || win_size.ws_col == 0 || win_size.ws_row == 0 )
2015-05-23 13:35:12 +02:00
{
2018-10-24 00:16:45 +02:00
term_geometry.setPos (1, 1);
// Use COLUMNS or fallback to the xterm default width of 80 characters
uInt Columns = env2uint ("COLUMNS");
term_geometry.setWidth( ( Columns == 0) ? 80 : Columns);
// Use LINES or fallback to the xterm default height of 24 characters
uInt Lines = env2uint ("LINES");
term_geometry.setHeight( ( Lines == 0 ) ? 24 : Lines);
2015-05-23 13:35:12 +02:00
}
2015-10-07 02:36:38 +02:00
else
2015-05-23 13:35:12 +02:00
{
term_geometry.setRect(1, 1, win_size.ws_col, win_size.ws_row);
2015-10-07 02:36:38 +02:00
}
if ( opti_move )
opti_move->setTermSize ( term_geometry.getWidth()
, term_geometry.getHeight() );
2015-10-07 02:36:38 +02:00
}
2015-05-23 13:35:12 +02:00
2015-10-07 02:36:38 +02:00
//----------------------------------------------------------------------
void FTerm::setTermSize (const FSize& size)
2015-10-07 02:36:38 +02:00
{
// Set xterm size
xterm->setTermSize (size);
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FTerm::setTermTitle (const FString& title)
2015-05-23 13:35:12 +02:00
{
// Set the xterm window title
xterm->setTitle (title);
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FTerm::setKDECursor (fc::kdeKonsoleCursorShape style)
2015-05-23 13:35:12 +02:00
{
// Set cursor style in KDE konsole
if ( isKdeTerminal() )
2015-05-23 13:35:12 +02:00
{
oscPrefix();
putstringf (OSC "50;CursorShape=%d" BEL, style);
oscPostfix();
std::fflush(stdout);
}
}
//----------------------------------------------------------------------
void FTerm::saveColorMap()
{
#if defined(__linux__)
linux->saveColorMap();
#endif
}
//----------------------------------------------------------------------
void FTerm::resetColorMap()
{
const auto& oc = TCAP(fc::t_orig_colors);
const auto& op = TCAP(fc::t_orig_pair);
2018-05-03 04:54:51 +02:00
if ( oc )
putstring (oc);
#if defined(__linux__)
else
linux->resetColorMap();
#endif
2015-10-07 02:36:38 +02:00
2018-05-03 04:54:51 +02:00
if ( op )
putstring (op);
std::fflush(stdout);
}
2015-10-01 03:48:58 +02:00
//----------------------------------------------------------------------
2018-11-07 22:06:58 +01:00
void FTerm::setPalette (FColor index, int r, int g, int b)
{
// Redefine RGB color value for a palette entry
const auto& Ic = TCAP(fc::t_initialize_color);
const auto& Ip = TCAP(fc::t_initialize_pair);
2015-10-01 03:48:58 +02:00
index = FOptiAttr::vga2ansi(index);
2015-10-07 21:32:30 +02:00
if ( Ic || Ip )
{
const char* color_str = "";
2015-10-07 21:32:30 +02:00
int rr = (r * 1001) / 256
, gg = (g * 1001) / 256
, bb = (b * 1001) / 256;
if ( Ic )
color_str = tparm(Ic, index, rr, gg, bb, 0, 0, 0, 0, 0);
else if ( Ip )
color_str = tparm(Ip, index, 0, 0, 0, rr, gg, bb, 0, 0);
2015-10-07 21:32:30 +02:00
putstring (color_str);
}
#if defined(__linux__)
else
{
linux->setPalette(index, r, g, b);
}
#endif
2015-10-07 21:32:30 +02:00
std::fflush(stdout);
}
2015-10-07 21:32:30 +02:00
//----------------------------------------------------------------------
#if defined(UNIT_TEST)
void FTerm::setBeep (int Hz, int ms)
{
linux->setBeep (Hz, ms);
freebsd->setBeep (Hz, ms);
openbsd->setBeep (Hz, ms);
}
#elif defined(__linux__)
void FTerm::setBeep (int Hz, int ms)
{
linux->setBeep (Hz, ms);
}
#elif defined(__FreeBSD__) || defined(__DragonFly__)
void FTerm::setBeep (int Hz, int ms)
{
freebsd->setBeep (Hz, ms);
}
#elif defined(__NetBSD__) || defined(__OpenBSD__)
void FTerm::setBeep (int Hz, int ms)
{
openbsd->setBeep (Hz, ms);
}
#else
void FTerm::setBeep (int, int)
{ }
#endif // defined(__linux__)
2015-10-07 21:32:30 +02:00
//----------------------------------------------------------------------
void FTerm::resetBeep()
{
#if defined(UNIT_TEST)
linux->resetBeep();
freebsd->resetBeep();
openbsd->resetBeep();
#elif defined(__linux__)
linux->resetBeep();
#elif defined(__FreeBSD__) || defined(__DragonFly__)
freebsd->resetBeep();
#elif defined(__NetBSD__) || defined(__OpenBSD__)
openbsd->resetBeep();
#endif
2015-10-07 02:36:38 +02:00
}
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
void FTerm::beep()
{
2017-09-11 03:06:02 +02:00
if ( TCAP(fc::t_bell) )
{
2017-09-11 03:06:02 +02:00
putstring (TCAP(fc::t_bell));
std::fflush(stdout);
}
}
//----------------------------------------------------------------------
void FTerm::setEncoding (fc::encoding enc)
{
data->setTermEncoding (enc);
assert ( enc == fc::UTF8
|| enc == fc::VT100 // VT100 line drawing
|| enc == fc::PC // CP-437
|| enc == fc::ASCII );
// Set the new Fputchar function pointer
switch ( enc )
{
case fc::UTF8:
Fputchar = &FTerm::putchar_UTF8;
break;
case fc::VT100:
case fc::PC:
if ( isXTerminal() && data->hasUTF8Console() )
Fputchar = &FTerm::putchar_UTF8;
2017-08-12 20:10:27 +02:00
else
Fputchar = &FTerm::putchar_ASCII;
break;
case fc::ASCII:
case fc::UNKNOWN:
case fc::NUM_OF_ENCODINGS:
Fputchar = &FTerm::putchar_ASCII;
}
if ( isLinuxTerm() )
{
if ( enc == fc::VT100 || enc == fc::PC )
{
2019-08-25 22:16:00 +02:00
char* empty{nullptr};
opti_move->set_tabular (empty);
}
else
2017-09-11 03:06:02 +02:00
opti_move->set_tabular (TCAP(fc::t_tab));
}
}
2015-10-07 02:36:38 +02:00
//----------------------------------------------------------------------
fc::encoding FTerm::getEncoding()
{
return data->getTermEncoding();
}
//----------------------------------------------------------------------
std::string FTerm::getEncodingString()
2015-10-07 02:36:38 +02:00
{
auto term_encoding = data->getTermEncoding();
auto& encoding_list = data->getEncodingList();
auto end = encoding_list.end();
2015-10-07 21:32:30 +02:00
for (auto it = encoding_list.begin(); it != end; ++it )
if ( it->second == term_encoding )
return it->first;
2015-10-07 21:32:30 +02:00
return "";
}
//----------------------------------------------------------------------
bool FTerm::charEncodable (wchar_t c)
{
wchar_t ch = charEncode(c);
return bool(ch > 0 && ch != c);
}
//----------------------------------------------------------------------
wchar_t FTerm::charEncode (wchar_t c)
{
return charEncode (c, data->getTermEncoding());
}
//----------------------------------------------------------------------
wchar_t FTerm::charEncode (wchar_t c, fc::encoding enc)
{
wchar_t ch_enc = c;
2019-08-25 22:16:00 +02:00
for (std::size_t i{0}; i <= fc::lastCharItem; i++)
{
if ( fc::character[i][fc::UTF8] == uInt(c) )
{
ch_enc = wchar_t(fc::character[i][enc]);
break;
}
}
if ( enc == fc::PC && ch_enc == c )
ch_enc = finalcut::unicode_to_cp437(c);
return ch_enc;
}
//----------------------------------------------------------------------
bool FTerm::scrollTermForward()
{
2017-09-11 03:06:02 +02:00
if ( TCAP(fc::t_scroll_forward) )
2015-05-23 13:35:12 +02:00
{
2017-09-11 03:06:02 +02:00
putstring (TCAP(fc::t_scroll_forward));
std::fflush(stdout);
return true;
}
2015-10-07 02:36:38 +02:00
return false;
}
2015-10-07 02:36:38 +02:00
//----------------------------------------------------------------------
bool FTerm::scrollTermReverse()
{
2017-09-11 03:06:02 +02:00
if ( TCAP(fc::t_scroll_reverse) )
{
2017-09-11 03:06:02 +02:00
putstring (TCAP(fc::t_scroll_reverse));
std::fflush(stdout);
return true;
2015-05-23 13:35:12 +02:00
}
return false;
2015-10-07 02:36:38 +02:00
}
//----------------------------------------------------------------------
2019-07-01 01:07:54 +02:00
void FTerm::putstring (const char str[], int affcnt)
{
2019-09-29 22:28:58 +02:00
if ( ! fsys )
getFSystem();
2019-07-01 01:07:54 +02:00
fsys->tputs (str, affcnt, FTerm::putchar_ASCII);
}
2015-10-07 02:36:38 +02:00
//----------------------------------------------------------------------
int FTerm::putchar_ASCII (int c)
{
2019-09-29 22:28:58 +02:00
if ( ! fsys )
getFSystem();
2019-07-01 01:07:54 +02:00
if ( fsys->putchar(char(c)) == EOF )
return 0;
else
return 1;
}
2015-10-07 02:36:38 +02:00
//----------------------------------------------------------------------
int FTerm::putchar_UTF8 (int c)
{
2019-09-29 22:28:58 +02:00
if ( ! fsys )
getFSystem();
if ( c < 0x80 )
{
// 1 Byte (7-bit): 0xxxxxxx
2019-07-01 01:07:54 +02:00
fsys->putchar (c);
return 1;
}
else if ( c < 0x800 )
{
// 2 byte (11-bit): 110xxxxx 10xxxxxx
2019-07-01 01:07:54 +02:00
fsys->putchar (0xc0 | (c >> 6) );
fsys->putchar (0x80 | (c & 0x3f) );
return 2;
}
else if ( c < 0x10000 )
{
// 3 byte (16-bit): 1110xxxx 10xxxxxx 10xxxxxx
2019-07-01 01:07:54 +02:00
fsys->putchar (0xe0 | (c >> 12) );
fsys->putchar (0x80 | ((c >> 6) & 0x3f) );
fsys->putchar (0x80 | (c & 0x3f) );
return 3;
}
else if ( c < 0x200000 )
{
// 4 byte (21-bit): 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
2019-07-01 01:07:54 +02:00
fsys->putchar (0xf0 | (c >> 18) );
fsys->putchar (0x80 | ((c >> 12) & 0x3f) );
fsys->putchar (0x80 | ((c >> 6) & 0x3f) );
fsys->putchar (0x80 | (c & 0x3f));
return 4;
}
else
return EOF;
}
2015-10-07 02:36:38 +02:00
// protected methods of FTerm
//----------------------------------------------------------------------
void FTerm::initScreenSettings()
{
#if defined(__linux__)
// Important: Do not use setNewFont() or setVGAFont() after
// the console character mapping has been initialized
linux->initCharMap();
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(UNIT_TEST)
freebsd->initCharMap();
#endif
// set xterm underline cursor
xterm->setCursorStyle (fc::blinking_underline);
// set xterm color settings to defaults
xterm->setDefaults();
}
//----------------------------------------------------------------------
char* FTerm::changeAttribute ( charData*& term_attr
, charData*& next_attr )
{
return opti_attr->changeAttribute (term_attr, next_attr);
}
//----------------------------------------------------------------------
void FTerm::changeTermSizeFinished()
{
data->setTermResized(false);
}
//----------------------------------------------------------------------
void FTerm::exitWithMessage (const FString& message)
{
// Exit the programm
if ( init_term_object )
init_term_object->finish();
std::fflush (stderr);
std::fflush (stdout);
if ( ! message.isEmpty() )
std::cerr << "Warning: " << message << std::endl;
std::exit (EXIT_FAILURE);
}
2015-10-07 02:36:38 +02:00
// private methods of FTerm
//----------------------------------------------------------------------
inline FStartOptions& FTerm::getStartOptions()
{
return FStartOptions::getFStartOptions();
}
//----------------------------------------------------------------------
void FTerm::init_global_values (bool disable_alt_screen)
{
// Initialize global values
// Preset to false
data->setNewFont(false);
// Sets alternate screen usage
data->useAlternateScreen(! disable_alt_screen);
// Initialize xterm object
xterm->init();
if ( ! getStartOptions().terminal_detection )
term_detection->setTerminalDetection (false);
#if DEBUG
debug_data->init();
#endif
}
//----------------------------------------------------------------------
void FTerm::init_terminal_device_path()
{
2019-08-25 22:16:00 +02:00
char termfilename[256]{};
int stdout_no = FTermios::getStdOut();
if ( ttyname_r(stdout_no, termfilename, sizeof(termfilename)) )
termfilename[0] = '\0';
data->setTermFileName(termfilename);
}
//----------------------------------------------------------------------
void FTerm::oscPrefix()
{
if ( isTmuxTerm() )
{
// tmux device control string
putstring (ESC "Ptmux;" ESC);
}
else if ( isScreenTerm() )
{
// GNU Screen device control string
putstring (ESC "P");
}
}
//----------------------------------------------------------------------
void FTerm::oscPostfix()
{
if ( isScreenTerm() || isTmuxTerm() )
{
// GNU Screen/tmux string terminator
putstring (ESC "\\");
}
}
//----------------------------------------------------------------------
void FTerm::init_alt_charset()
{
// Read the used VT100 pairs
std::unordered_map<uChar, uChar> vt100_alt_char;
if ( TCAP(fc::t_acs_chars) )
{
2019-08-25 22:16:00 +02:00
for (std::size_t n{0}; TCAP(fc::t_acs_chars)[n]; n += 2)
{
// insert the VT100 key/value pairs into a map
uChar p1 = uChar(TCAP(fc::t_acs_chars)[n]);
uChar p2 = uChar(TCAP(fc::t_acs_chars)[n + 1]);
vt100_alt_char[p1] = p2;
}
}
enum column
{
vt100_key = 0,
utf8_char = 1
};
// Update array 'character' with discovered VT100 pairs
2019-08-25 22:16:00 +02:00
for (std::size_t n{0}; n <= fc::lastKeyItem; n++ )
{
uChar keyChar = uChar(fc::vt100_key_to_utf8[n][vt100_key]);
uChar altChar = uChar(vt100_alt_char[keyChar]);
uInt utf8char = uInt(fc::vt100_key_to_utf8[n][utf8_char]);
fc::encoding num{fc::NUM_OF_ENCODINGS};
uInt* p = std::find ( fc::character[0]
, fc::character[fc::lastCharItem] + num
, utf8char );
if ( p != fc::character[fc::lastCharItem] + num ) // found in character
{
int item = int(std::distance(fc::character[0], p) / num);
if ( altChar ) // update alternate character set
fc::character[item][fc::VT100] = altChar;
else // delete VT100 char in character
fc::character[item][fc::VT100] = 0;
}
}
}
//----------------------------------------------------------------------
void FTerm::init_pc_charset()
{
2019-08-25 22:16:00 +02:00
bool reinit{false};
2015-05-23 13:35:12 +02:00
// rxvt does not support pc charset
if ( isRxvtTerminal() || isUrxvtTerminal() )
return;
if ( isGnomeTerminal() || isLinuxTerm() )
{
// Fallback if tcap "S2" is not found
2017-09-11 03:06:02 +02:00
if ( ! TCAP(fc::t_enter_pc_charset_mode) )
{
if ( data->hasUTF8Console() )
{
// Select iso8859-1 + null mapping
2017-09-11 03:06:02 +02:00
TCAP(fc::t_enter_pc_charset_mode) = \
C_STR(ESC "%@" ESC "(U");
}
else
{
// Select null mapping
2017-09-11 03:06:02 +02:00
TCAP(fc::t_enter_pc_charset_mode) = \
C_STR(ESC "(U");
}
2017-09-11 03:06:02 +02:00
opti_attr->set_enter_pc_charset_mode \
(TCAP(fc::t_enter_pc_charset_mode));
reinit = true;
}
// Fallback if tcap "S3" is not found
2017-09-11 03:06:02 +02:00
if ( ! TCAP(fc::t_exit_pc_charset_mode) )
{
if ( data->hasUTF8Console() )
{
// Select ascii mapping + utf8
2017-09-11 03:06:02 +02:00
TCAP(fc::t_exit_pc_charset_mode) = \
C_STR(ESC "(B" ESC "%G");
}
else
{
// Select ascii mapping
2017-09-11 03:06:02 +02:00
TCAP(fc::t_enter_pc_charset_mode) = \
C_STR(ESC "(B");
}
2017-09-11 03:06:02 +02:00
opti_attr->set_exit_pc_charset_mode \
2017-11-30 02:38:55 +01:00
(TCAP(fc::t_exit_pc_charset_mode));
reinit = true;
}
}
if ( reinit )
opti_attr->initialize();
}
2016-10-09 02:06:06 +02:00
//----------------------------------------------------------------------
void FTerm::init_cygwin_charmap()
2016-10-09 02:06:06 +02:00
{
// Replace don't printable PC charset characters in a Cygwin terminal
2015-05-23 13:35:12 +02:00
if ( ! isCygwinTerminal() )
return;
2019-01-03 21:38:19 +01:00
// PC encoding changes
2019-08-25 22:16:00 +02:00
for (std::size_t i{0}; i <= fc::lastCharItem; i++ )
{
if ( fc::character[i][fc::UTF8] == fc::BlackUpPointingTriangle ) // ▲
fc::character[i][fc::PC] = 0x18;
if ( fc::character[i][fc::UTF8] == fc::BlackDownPointingTriangle ) // ▼
fc::character[i][fc::PC] = 0x19;
if ( fc::character[i][fc::UTF8] == fc::InverseBullet // ◘
|| fc::character[i][fc::UTF8] == fc::InverseWhiteCircle // ◙
|| fc::character[i][fc::UTF8] == fc::UpDownArrow // ↕
|| fc::character[i][fc::UTF8] == fc::LeftRightArrow // ↔
|| fc::character[i][fc::UTF8] == fc::DoubleExclamationMark // ‼
|| fc::character[i][fc::UTF8] == fc::BlackRectangle // ▬
|| fc::character[i][fc::UTF8] == fc::RightwardsArrow // →
|| fc::character[i][fc::UTF8] == fc::Section // §
|| fc::character[i][fc::UTF8] == fc::SquareRoot ) // SquareRoot √
fc::character[i][fc::PC] = fc::character[i][fc::ASCII];
}
2019-01-03 21:38:19 +01:00
// General encoding changes
charSubstitution& sub_map = data->getCharSubstitutionMap();
2019-01-03 21:38:19 +01:00
sub_map[L''] = L'*';
sub_map[L''] = L'*';
sub_map[L''] = L'*';
sub_map[L''] = L'*';
sub_map[L''] = L'*';
sub_map[L''] = L'';
sub_map[L''] = L'x';
sub_map[L'ˣ'] = L'`';
}
//----------------------------------------------------------------------
void FTerm::init_fixed_max_color()
{
// Initialize maximum number of colors for known terminals
if ( isCygwinTerminal()
|| isPuttyTerminal()
|| isTeraTerm()
|| isRxvtTerminal() )
{
FTermcap::max_color = 16;
}
}
//----------------------------------------------------------------------
void FTerm::init_teraterm_charmap()
{
// Tera Term can't print ascii characters < 0x20
if ( ! isTeraTerm() )
return;
2019-08-25 22:16:00 +02:00
for (std::size_t i{0}; i <= fc::lastCharItem; i++ )
if ( fc::character[i][fc::PC] < 0x20 )
fc::character[i][fc::PC] = fc::character[i][fc::ASCII];
}
//----------------------------------------------------------------------
void FTerm::init_keyboard()
{
keyboard->init();
}
//----------------------------------------------------------------------
void FTerm::init_termcap()
{
2018-10-08 04:14:20 +02:00
// Initialize the terminal capabilities
2018-02-19 01:36:38 +01:00
FTermcap::init();
2018-02-19 01:36:38 +01:00
}
2018-02-19 01:36:38 +01:00
//----------------------------------------------------------------------
2018-10-08 04:14:20 +02:00
void FTerm::init_quirks()
2018-02-19 01:36:38 +01:00
{
2018-10-08 04:14:20 +02:00
// Initialize terminal quirks
2018-08-09 00:04:00 +02:00
FTermcapQuirks quirks;
2018-10-08 04:14:20 +02:00
quirks.terminalFixup(); // Fix terminal quirks
}
//----------------------------------------------------------------------
2018-10-08 04:14:20 +02:00
void FTerm::init_optiMove()
{
// Duration precalculation of the cursor movement strings
FOptiMove::termEnv optimove_env =
{
TCAP(fc::t_cursor_home),
TCAP(fc::t_carriage_return),
TCAP(fc::t_cursor_to_ll),
TCAP(fc::t_tab),
TCAP(fc::t_back_tab),
TCAP(fc::t_cursor_up),
TCAP(fc::t_cursor_down),
TCAP(fc::t_cursor_left),
TCAP(fc::t_cursor_right),
TCAP(fc::t_cursor_address),
TCAP(fc::t_column_address),
TCAP(fc::t_row_address),
TCAP(fc::t_parm_up_cursor),
TCAP(fc::t_parm_down_cursor),
TCAP(fc::t_parm_left_cursor),
TCAP(fc::t_parm_right_cursor),
TCAP(fc::t_erase_chars),
TCAP(fc::t_repeat_char),
TCAP(fc::t_clr_bol),
2019-09-08 02:04:24 +02:00
TCAP(fc::t_clr_eol),
FTermcap::tabstop,
FTermcap::automatic_left_margin,
FTermcap::eat_nl_glitch
};
opti_move->setTermEnvironment(optimove_env);
}
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
2018-10-08 04:14:20 +02:00
void FTerm::init_optiAttr()
{
// Setting video attribute optimization
FOptiAttr::termEnv optiattr_env =
{
TCAP(fc::t_enter_bold_mode),
TCAP(fc::t_exit_bold_mode),
TCAP(fc::t_enter_dim_mode),
TCAP(fc::t_exit_dim_mode),
TCAP(fc::t_enter_italics_mode),
TCAP(fc::t_exit_italics_mode),
TCAP(fc::t_enter_underline_mode),
TCAP(fc::t_exit_underline_mode),
TCAP(fc::t_enter_blink_mode),
TCAP(fc::t_exit_blink_mode),
TCAP(fc::t_enter_reverse_mode),
TCAP(fc::t_exit_reverse_mode),
TCAP(fc::t_enter_standout_mode),
TCAP(fc::t_exit_standout_mode),
TCAP(fc::t_enter_secure_mode),
TCAP(fc::t_exit_secure_mode),
TCAP(fc::t_enter_protected_mode),
TCAP(fc::t_exit_protected_mode),
TCAP(fc::t_enter_crossed_out_mode),
TCAP(fc::t_exit_crossed_out_mode),
TCAP(fc::t_enter_dbl_underline_mode),
TCAP(fc::t_exit_dbl_underline_mode),
TCAP(fc::t_set_attributes),
TCAP(fc::t_exit_attribute_mode),
TCAP(fc::t_enter_alt_charset_mode),
TCAP(fc::t_exit_alt_charset_mode),
TCAP(fc::t_enter_pc_charset_mode),
TCAP(fc::t_exit_pc_charset_mode),
TCAP(fc::t_set_a_foreground),
TCAP(fc::t_set_a_background),
TCAP(fc::t_set_foreground),
TCAP(fc::t_set_background),
TCAP(fc::t_orig_pair),
TCAP(fc::t_orig_pair),
2019-09-08 02:04:24 +02:00
TCAP(fc::t_orig_colors),
FTermcap::max_color,
FTermcap::attr_without_color,
FTermcap::ansi_default_color
};
opti_attr->setTermEnvironment(optiattr_env);
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FTerm::init_font()
{
if ( getStartOptions().vgafont && ! setVGAFont() )
exitWithMessage ("VGAfont is not supported by this terminal");
if ( getStartOptions().newfont && ! setNewFont() )
exitWithMessage ("Newfont is not supported by this terminal");
}
//----------------------------------------------------------------------
void FTerm::init_locale()
{
// Init current locale
const char* termtype = data->getTermType();
2019-08-25 22:16:00 +02:00
const char* locale_name = std::setlocale (LC_ALL, "");
std::setlocale (LC_NUMERIC, "");
// Get XTERM_LOCALE
2019-08-25 22:16:00 +02:00
const char* locale_xterm = std::getenv("XTERM_LOCALE");
// set LC_ALL to XTERM_LOCALE
if ( locale_xterm )
locale_name = std::setlocale (LC_ALL, locale_xterm);
// TeraTerm can not show UTF-8 character
if ( isTeraTerm() && ! std::strcmp(nl_langinfo(CODESET), "UTF-8") )
locale_name = std::setlocale (LC_ALL, "C");
// Kterm
if ( isKtermTerminal() && ! std::strcmp(nl_langinfo(CODESET), "UTF-8") )
locale_name = std::setlocale (LC_ALL, "C");
// Sun (color) workstation console can't show UTF-8 character
if ( std::strncmp(termtype, "sun", 3) == 0
&& ! std::strcmp(nl_langinfo(CODESET), "UTF-8") )
locale_name = std::setlocale (LC_ALL, "C");
// Try to found a meaningful content for locale_name
if ( locale_name )
locale_name = std::setlocale (LC_CTYPE, 0);
else
{
locale_name = std::getenv("LC_ALL");
if ( ! locale_name )
{
locale_name = std::getenv("LC_CTYPE");
if ( ! locale_name )
locale_name = std::getenv("LANG");
}
}
// Fallback to C
if ( ! locale_name )
std::setlocale (LC_ALL, "C");
}
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
void FTerm::init_encoding()
2015-05-23 13:35:12 +02:00
{
// detect encoding and set the Fputchar function pointer
2019-08-25 22:16:00 +02:00
bool force_vt100{false}; // VT100 line drawing (G1 character set)
2018-02-19 23:02:54 +01:00
init_encoding_set();
if ( isRxvtTerminal() && ! isUrxvtTerminal() )
force_vt100 = true; // This rxvt terminal does not support utf-8
2018-02-19 23:02:54 +01:00
init_term_encoding();
init_pc_charset();
init_individual_term_encoding();
if ( force_vt100 )
init_force_vt100_encoding();
else
2018-02-19 23:02:54 +01:00
init_utf8_without_alt_charset();
init_tab_quirks();
if ( getStartOptions().encoding != fc::UNKNOWN )
{
setEncoding(getStartOptions().encoding);
}
2018-02-19 23:02:54 +01:00
}
//----------------------------------------------------------------------
inline void FTerm::init_encoding_set()
{
// Define the encoding set
2018-02-19 23:02:54 +01:00
auto& encoding_list = data->getEncodingList();
encoding_list["UTF8"] = fc::UTF8;
encoding_list["UTF-8"] = fc::UTF8;
encoding_list["VT100"] = fc::VT100; // VT100 line drawing
encoding_list["PC"] = fc::PC; // CP-437
encoding_list["ASCII"] = fc::ASCII;
2018-02-19 23:02:54 +01:00
}
2018-02-19 23:02:54 +01:00
//----------------------------------------------------------------------
void FTerm::init_term_encoding()
{
int stdout_no = FTermios::getStdOut();
const char* termtype = data->getTermType();
2019-09-29 22:28:58 +02:00
if ( ! fsys )
getFSystem();
if ( fsys->isTTY(stdout_no)
2017-11-26 22:37:18 +01:00
&& ! std::strcmp(nl_langinfo(CODESET), "UTF-8") )
2015-05-23 13:35:12 +02:00
{
data->setUTF8Console(true);
data->setTermEncoding (fc::UTF8);
Fputchar = &FTerm::putchar_UTF8; // function pointer
data->setUTF8(true);
setUTF8(true);
keyboard->enableUTF8();
2015-05-23 13:35:12 +02:00
}
else if ( fsys->isTTY(stdout_no)
2017-11-26 22:37:18 +01:00
&& (std::strlen(termtype) > 0)
&& (TCAP(fc::t_exit_alt_charset_mode) != 0) )
2015-05-23 13:35:12 +02:00
{
data->setVT100Console (true);
data->setTermEncoding (fc::VT100);
Fputchar = &FTerm::putchar_ASCII; // function pointer
}
else
{
data->setASCIIConsole (true);
data->setTermEncoding (fc::ASCII);
Fputchar = &FTerm::putchar_ASCII; // function pointer
2015-05-23 13:35:12 +02:00
}
2018-02-19 23:02:54 +01:00
}
2015-05-23 13:35:12 +02:00
2018-02-19 23:02:54 +01:00
//----------------------------------------------------------------------
void FTerm::init_individual_term_encoding()
{
if ( isNewFont()
|| (isPuttyTerminal() && ! data->isUTF8())
|| (isTeraTerm() && ! data->isUTF8()) )
2015-05-23 13:35:12 +02:00
{
data->setTermEncoding (fc::PC);
Fputchar = &FTerm::putchar_ASCII; // function pointer
if ( hasUTF8() && getStartOptions().encoding == fc::UNKNOWN )
{
if ( isXTerminal() )
Fputchar = &FTerm::putchar_UTF8; // function pointer
}
2015-05-23 13:35:12 +02:00
}
2018-02-19 23:02:54 +01:00
}
2015-05-23 13:35:12 +02:00
2018-02-19 23:02:54 +01:00
//----------------------------------------------------------------------
void FTerm::init_force_vt100_encoding()
2018-02-19 23:02:54 +01:00
{
data->setVT100Console(true);
data->setTermEncoding (fc::VT100);
Fputchar = &FTerm::putchar_ASCII; // function pointer
2018-02-19 23:02:54 +01:00
}
//----------------------------------------------------------------------
void FTerm::init_utf8_without_alt_charset()
{
// Fall back to ascii for utf-8 terminals that
// do not support VT100 line drawings
if ( FTermcap::no_utf8_acs_chars && data->isUTF8()
&& data->getTermEncoding() == fc::VT100 )
{
data->setASCIIConsole(true);
data->setTermEncoding (fc::ASCII);
Fputchar = &FTerm::putchar_ASCII; // function pointer
}
2018-02-19 23:02:54 +01:00
}
2018-02-19 23:02:54 +01:00
//----------------------------------------------------------------------
void FTerm::init_tab_quirks()
{
2017-03-26 20:40:04 +02:00
// In some alternative character sets, a tab character prints a '○'
// on the terminal and does not move the cursor to the next tab stop
// position
2018-02-19 23:02:54 +01:00
auto enc = data->getTermEncoding();
if ( enc == fc::VT100 || enc == fc::PC )
{
2019-08-25 22:16:00 +02:00
char* empty{nullptr};
opti_move->set_tabular (empty);
}
2015-05-23 13:35:12 +02:00
}
2018-05-27 22:58:22 +02:00
//----------------------------------------------------------------------
void FTerm::init_captureFontAndTitle()
{
// Save the used xterm font and window title
xterm->captureFontAndTitle();
2018-12-26 23:41:49 +01:00
const auto font = xterm->getFont();
const auto title = xterm->getTitle();
2018-05-27 22:58:22 +02:00
if ( font )
data->setXtermFont(*font);
2018-05-27 22:58:22 +02:00
if ( title )
data->setXtermTitle(*title);
2018-05-27 22:58:22 +02:00
}
//----------------------------------------------------------------------
2018-10-09 00:33:26 +02:00
inline bool FTerm::hasNoFontSettingOption()
{
2018-10-09 00:33:26 +02:00
if ( isGnomeTerminal()
|| isKdeTerminal()
|| isPuttyTerminal()
|| isTeraTerm()
|| isCygwinTerminal()
|| isMinttyTerm() )
return true;
2018-10-09 00:33:26 +02:00
return false;
}
//----------------------------------------------------------------------
void FTerm::redefineColorPalette()
{
// Redefine the color palette
if ( ! canChangeColorPalette() )
return;
resetColorMap();
saveColorMap();
if ( getMaxColor() >= 16 )
FColorPalette::set16ColorPalette (FTerm::setPalette);
else // 8 colors
FColorPalette::set8ColorPalette (FTerm::setPalette);
}
//----------------------------------------------------------------------
void FTerm::restoreColorPalette()
{
2018-10-09 00:33:26 +02:00
if ( ! canChangeColorPalette() )
return;
// Reset screen settings
if ( getMaxColor() >= 16 )
FColorPalette::reset16ColorPalette (FTerm::setPalette);
else // 8 colors
FColorPalette::reset8ColorPalette (FTerm::setPalette);
xterm->resetColorMap();
resetColorMap();
}
//----------------------------------------------------------------------
void FTerm::setInsertCursorStyle()
{
xterm->setCursorStyle (fc::blinking_underline);
setKDECursor(fc::UnderlineCursor);
#if defined(__linux__)
linux->setCursorStyle (fc::underscore_cursor);
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(UNIT_TEST)
freebsd->setCursorStyle (fc::destructive_cursor);
#endif
if ( isUrxvtTerminal() )
xterm->setCursorColor ("rgb:ffff/ffff/ffff");
}
//----------------------------------------------------------------------
void FTerm::setOverwriteCursorStyle()
{
xterm->setCursorStyle (fc::steady_block);
setKDECursor(fc::BlockCursor);
#if defined(__linux__)
linux->setCursorStyle (fc::full_block_cursor);
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(UNIT_TEST)
freebsd->setCursorStyle (fc::normal_cursor);
#endif
if ( isUrxvtTerminal() )
xterm->setCursorColor ("rgb:eeee/0000/0000");
}
//----------------------------------------------------------------------
char* FTerm::enableCursorString()
{
// Returns the cursor enable string
static constexpr std::size_t SIZE = 32;
2019-08-25 22:16:00 +02:00
static char enable_str[SIZE]{};
const auto& vs = TCAP(fc::t_cursor_visible);
const auto& ve = TCAP(fc::t_cursor_normal);
if ( ve )
std::strncpy (enable_str, ve, SIZE - 1);
else if ( vs )
std::strncpy (enable_str, vs, SIZE - 1);
#if defined(__linux__)
if ( isLinuxTerm() )
{
// Restore the last used Linux console cursor style
const char* cstyle = linux->getCursorStyleString();
std::strncat (enable_str, cstyle, SIZE - std::strlen(enable_str) - 1);
}
#endif // defined(__linux__)
enable_str[SIZE - 1] = '\0';
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(UNIT_TEST)
if ( isFreeBSDTerm() )
{
// Restore the last used FreeBSD console cursor style
freebsd->setCursorStyle (freebsd->getCursorStyle());
}
#endif // defined(__FreeBSD__) || defined(__DragonFly__) || defined(UNIT_TEST)
return enable_str;
}
//----------------------------------------------------------------------
char* FTerm::disableCursorString()
{
// Returns the cursor disable string
const auto& vi = TCAP(fc::t_cursor_invisible);
if ( vi )
return vi;
return 0;
}
//----------------------------------------------------------------------
void FTerm::enableMouse()
{
2018-10-09 00:33:26 +02:00
// Enable the terminal mouse support
if ( ! getStartOptions().mouse_support )
2018-10-09 00:33:26 +02:00
return;
2019-08-25 22:16:00 +02:00
bool gpm_mouse{false};
bool xterm_mouse{false};
2018-01-16 16:16:29 +01:00
#if defined(__linux__)
if ( isLinuxTerm() && openConsole() == 0 )
{
if ( linux->isLinuxConsole() )
gpm_mouse = true;
closeConsole();
}
#endif // defined(__linux__)
if ( TCAP(fc::t_key_mouse) && ! isLinuxTerm() )
xterm_mouse = true;
keyboard->enableMouseSequences();
2018-12-28 22:57:43 +01:00
mouse->setMaxWidth (uInt16(getColumnNumber()));
mouse->setMaxHeight (uInt16(getLineNumber()));
// Enable the linux general purpose mouse (gpm) server
mouse->useGpmMouse (gpm_mouse);
// Enable xterm mouse support
mouse->useXtermMouse (xterm_mouse);
mouse->enable();
}
//----------------------------------------------------------------------
2018-10-09 00:33:26 +02:00
inline void FTerm::disableMouse()
{
2018-10-09 00:33:26 +02:00
// Disable the terminal mouse support
keyboard->disableMouseSequences();
mouse->disable();
}
2018-10-09 00:33:26 +02:00
//----------------------------------------------------------------------
inline void FTerm::enableKeypad()
{
// Enter 'keyboard_transmit' mode
if ( TCAP(fc::t_keypad_xmit) )
{
putstring (TCAP(fc::t_keypad_xmit));
std::fflush(stdout);
}
}
//----------------------------------------------------------------------
inline void FTerm::disableKeypad()
{
// Leave 'keyboard_transmit' mode
if ( TCAP(fc::t_keypad_local) )
{
putstring (TCAP(fc::t_keypad_local));
std::fflush(stdout);
}
}
//----------------------------------------------------------------------
inline void FTerm::enableAlternateCharset()
{
// Enable alternate charset
if ( TCAP(fc::t_enable_acs) )
{
putstring (TCAP(fc::t_enable_acs));
std::fflush(stdout);
}
}
//----------------------------------------------------------------------
inline void FTerm::enableApplicationEscKey()
{
// switch to application escape key mode
if ( isMinttyTerm() )
FTerm::putstring (CSI "?7727h");
}
//----------------------------------------------------------------------
inline void FTerm::disableApplicationEscKey()
{
// Switch to normal escape key mode
if ( isMinttyTerm() )
putstring (CSI "?7727l");
}
2018-02-04 19:42:30 +01:00
//----------------------------------------------------------------------
void FTerm::useAlternateScreenBuffer()
{
// Switch to the alternate screen
if ( ! hasAlternateScreen() )
2018-02-04 19:42:30 +01:00
return;
// Save current cursor position
if ( TCAP(fc::t_save_cursor) )
{
putstring (TCAP(fc::t_save_cursor));
std::fflush(stdout);
}
// Saves the screen and the cursor position
if ( TCAP(fc::t_enter_ca_mode) )
{
putstring (TCAP(fc::t_enter_ca_mode));
std::fflush(stdout);
}
}
//----------------------------------------------------------------------
void FTerm::useNormalScreenBuffer()
{
// Switch to the normal screen
if ( ! hasAlternateScreen() )
2018-02-04 19:42:30 +01:00
return;
// restores the screen and the cursor position
if ( TCAP(fc::t_exit_ca_mode) )
{
putstring (TCAP(fc::t_exit_ca_mode));
std::fflush(stdout);
}
// restore cursor to position of last save_cursor
if ( TCAP(fc::t_restore_cursor) )
{
putstring (TCAP(fc::t_restore_cursor));
std::fflush(stdout);
}
}
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
2017-12-21 00:45:04 +01:00
inline void FTerm::allocationValues()
2015-05-23 13:35:12 +02:00
{
getFTermData();
getFSystem();
getFOptiMove();
getFOptiAttr();
getFTermDetection();
getFTermXTerminal();
getFKeyboard();
getFMouseControl();
#if defined(__linux__)
getFTermLinux();
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(UNIT_TEST)
getFTermFreeBSD();
2019-07-14 18:30:35 +02:00
#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(UNIT_TEST)
getFTermOpenBSD();
#endif
#if DEBUG
getFTermDebugData();
#endif
2017-12-21 00:45:04 +01:00
}
//----------------------------------------------------------------------
inline void FTerm::deallocationValues()
{
#if DEBUG
if ( debug_data )
delete debug_data;
#endif
2019-07-14 18:30:35 +02:00
#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(UNIT_TEST)
if ( openbsd )
delete openbsd;
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(UNIT_TEST)
if ( freebsd )
delete freebsd;
2018-10-08 04:14:20 +02:00
#elif defined(__linux__)
if ( linux )
delete linux;
#endif
if ( mouse )
delete mouse;
if ( keyboard )
delete keyboard;
if ( xterm )
delete xterm;
if ( term_detection )
delete term_detection;
2017-12-21 00:45:04 +01:00
if ( opti_attr )
delete opti_attr;
if ( opti_move )
delete opti_move;
if ( fsys )
delete fsys;
if ( data )
delete data;
2017-12-21 00:45:04 +01:00
}
//----------------------------------------------------------------------
void FTerm::init (bool disable_alt_screen)
2017-12-21 00:45:04 +01:00
{
init_term_object = this;
2015-05-23 13:35:12 +02:00
// Initialize global values for all objects
2017-12-21 00:45:04 +01:00
allocationValues();
init_global_values(disable_alt_screen);
2015-05-23 13:35:12 +02:00
// Initialize termios
FTermios::init();
2017-09-11 03:06:02 +02:00
// Get pathname of the terminal device
init_terminal_device_path();
// Initialize Linux or *BSD console
2018-02-04 19:42:30 +01:00
initOSspecifics();
// Save termios settings
FTermios::storeTTYsettings();
2015-10-07 21:32:30 +02:00
// Get output baud rate
2018-10-09 00:33:26 +02:00
initBaudRate();
2015-05-23 13:35:12 +02:00
// Terminal detection
term_detection->detect();
setTermType (term_detection->getTermType());
// Set maximum number of colors for detected terminals
init_fixed_max_color();
// Initializes variables for the current terminal
init_termcap();
2018-10-08 04:14:20 +02:00
// Initialize terminal quirks
init_quirks();
// Initialize cursor movement optimization
init_optiMove();
// Initialize video attributes optimization
init_optiAttr();
// Initialize vt100 alternate character set
init_alt_charset();
// Pass the terminal capabilities to the keyboard object
keyboard->setTermcapMap (fc::Fkey);
// Initializes locale information
init_locale();
2015-05-23 13:35:12 +02:00
// Detect environment and set encoding
init_encoding();
// Initializes keyboard settings
init_keyboard();
// Enable the terminal mouse support
2018-10-09 00:33:26 +02:00
enableMouse();
// Activate meta key sends escape
if ( isXTerminal() )
xterm->metaSendsESC(true);
2017-04-11 00:30:27 +02:00
// switch to application escape key mode
2018-10-09 00:33:26 +02:00
enableApplicationEscKey();
// Enter 'keyboard_transmit' mode
2018-10-09 00:33:26 +02:00
enableKeypad();
// Switch to the alternate screen
2018-02-04 19:42:30 +01:00
useAlternateScreenBuffer();
2015-05-23 13:35:12 +02:00
// Enable alternate charset
2018-10-09 00:33:26 +02:00
enableAlternateCharset();
2015-05-23 13:35:12 +02:00
// Save the used xterm font and window title
2018-05-27 22:58:22 +02:00
init_captureFontAndTitle();
2018-10-02 01:03:44 +02:00
// KDE terminal cursor and cygwin + teraterm charmap correction
initTermspecifics();
// Redefine the color palette
if ( getStartOptions().color_change )
redefineColorPalette();
// Set 220 Hz beep (100 ms)
setBeep(220, 100);
// Set FTerm signal handler
setSignalHandler();
if ( ! getStartOptions().cursor_optimisation )
data->supportCursorOptimisation(false);
// Activate the VGA or the new graphic font
// (depending on the initialization values)
init_font();
2016-11-20 18:26:15 +01:00
// Turn off hardware echo
FTermios::unsetHardwareEcho();
2016-11-20 18:26:15 +01:00
// Switch to the raw mode
FTermios::setRawMode();
// The terminal is now initialized
term_initialized = true;
2015-05-23 13:35:12 +02:00
}
2018-02-04 19:42:30 +01:00
//----------------------------------------------------------------------
void FTerm::initOSspecifics()
{
#if defined(__linux__)
linux->init(); // Initialize Linux console
#if DEBUG
data->setFramebufferBpp (linux->getFramebufferBpp());
2018-02-04 19:42:30 +01:00
#endif
#endif // defined(__linux__)
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(UNIT_TEST)
if ( getStartOptions().meta_sends_escape )
freebsd->enableMetaSendsEscape();
else
freebsd->disableMetaSendsEscape();
if ( getStartOptions().change_cursorstyle )
freebsd->enableChangeCursorStyle();
else
freebsd->disableChangeCursorStyle();
freebsd->init(); // Initialize BSD console
2019-07-14 18:30:35 +02:00
#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(UNIT_TEST)
if ( getStartOptions().meta_sends_escape )
openbsd->enableMetaSendsEscape();
else
openbsd->disableMetaSendsEscape();
openbsd->init(); // Initialize wscons console
2018-02-04 19:42:30 +01:00
#endif
}
2018-10-02 01:03:44 +02:00
//----------------------------------------------------------------------
void FTerm::initTermspecifics()
{
if ( isKdeTerminal() )
setKDECursor(fc::UnderlineCursor);
if ( isCygwinTerminal() )
init_cygwin_charmap();
if ( isTeraTerm() )
init_teraterm_charmap();
}
2018-10-09 00:33:26 +02:00
//----------------------------------------------------------------------
void FTerm::initBaudRate()
{
int stdout_no = FTermios::getStdOut();
uInt baud = FTermios::getBaudRate();
data->setBaudrate(baud);
2019-09-29 22:28:58 +02:00
if ( ! fsys )
getFSystem();
if ( fsys->isTTY(stdout_no) )
2018-10-09 00:33:26 +02:00
opti_move->setBaudRate(int(baud));
}
//----------------------------------------------------------------------
void FTerm::finish()
{
// Set default signal handler
2018-12-26 23:41:49 +01:00
const auto& title = data->getXtermTitle();
resetSignalHandler();
if ( title && isXTerminal() && ! isRxvtTerminal() )
setTermTitle (title);
// Restore the saved termios settings
FTermios::restoreTTYsettings();
// Turn off all attributes
2017-09-11 03:06:02 +02:00
if ( TCAP(fc::t_exit_attribute_mode) )
{
2017-09-11 03:06:02 +02:00
putstring (TCAP(fc::t_exit_attribute_mode));
std::fflush(stdout);
}
// Turn off pc charset mode
2017-09-11 03:06:02 +02:00
if ( TCAP(fc::t_exit_pc_charset_mode) )
{
2017-09-11 03:06:02 +02:00
putstring (TCAP(fc::t_exit_pc_charset_mode));
std::fflush(stdout);
}
// Reset xterm color settings to default values
xterm->resetDefaults();
// Set xterm full block cursor
xterm->setCursorStyle (fc::steady_block);
// Restore the color palette
if ( getStartOptions().color_change )
restoreColorPalette();
2015-05-23 13:35:12 +02:00
2018-10-09 00:33:26 +02:00
// Switch to normal escape key mode
disableApplicationEscKey();
2018-02-04 19:42:30 +01:00
finishOSspecifics1();
if ( isKdeTerminal() )
setKDECursor(fc::BlockCursor);
2015-05-23 13:35:12 +02:00
resetBeep();
2015-05-23 13:35:12 +02:00
// Disable the terminal mouse support
if ( getStartOptions().mouse_support )
disableMouse();
2015-05-23 13:35:12 +02:00
// Deactivate meta key sends escape
if ( isXTerminal() )
xterm->metaSendsESC(false);
2017-04-11 00:30:27 +02:00
// Switch to the normal screen
2018-02-04 19:42:30 +01:00
useNormalScreenBuffer();
// leave 'keyboard_transmit' mode
2018-10-09 00:33:26 +02:00
disableKeypad();
2015-05-23 13:35:12 +02:00
finish_encoding();
if ( data->isNewFont() || data->isVGAFont() )
setOldFont();
2018-02-04 19:42:30 +01:00
deallocationValues();
}
//----------------------------------------------------------------------
void FTerm::finishOSspecifics1()
{
#if defined(__linux__)
linux->finish();
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(UNIT_TEST)
freebsd->finish();
2019-07-14 18:30:35 +02:00
#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(UNIT_TEST)
openbsd->finish();
2018-02-04 19:42:30 +01:00
#endif
}
//----------------------------------------------------------------------
void FTerm::finish_encoding()
2018-02-04 19:42:30 +01:00
{
2017-03-26 20:40:04 +02:00
#if defined(__linux__)
if ( isLinuxTerm() && data->hasUTF8Console() )
setUTF8(true);
2017-03-26 20:40:04 +02:00
#endif
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FTerm::setSignalHandler()
{
signal(SIGTERM, FTerm::signal_handler); // Termination signal
signal(SIGQUIT, FTerm::signal_handler); // Quit from keyboard (Ctrl-\)
signal(SIGINT, FTerm::signal_handler); // Keyboard interrupt (Ctrl-C)
signal(SIGABRT, FTerm::signal_handler); // Abort signal from abort(3)
signal(SIGILL, FTerm::signal_handler); // Illegal Instruction
signal(SIGSEGV, FTerm::signal_handler); // Invalid memory reference
signal(SIGWINCH, FTerm::signal_handler); // Window resize signal
}
//----------------------------------------------------------------------
void FTerm::resetSignalHandler()
{
signal(SIGWINCH, SIG_DFL); // Window resize signal
signal(SIGSEGV, SIG_DFL); // Invalid memory reference
signal(SIGILL, SIG_DFL); // Illegal Instruction
signal(SIGABRT, SIG_DFL); // Abort signal from abort(3)
signal(SIGINT, SIG_DFL); // Keyboard interrupt (Ctrl-C)
signal(SIGQUIT, SIG_DFL); // Quit from keyboard (Ctrl-\)
signal(SIGTERM, SIG_DFL); // Termination signal
}
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
void FTerm::signal_handler (int signum)
2015-05-23 13:35:12 +02:00
{
switch (signum)
2015-05-23 13:35:12 +02:00
{
case SIGWINCH:
if ( ! data )
break;
if ( data->hasTermResized() )
break;
// initialize a resize event to the root element
data->setTermResized(true);
break;
2015-05-23 13:35:12 +02:00
case SIGTERM:
case SIGQUIT:
case SIGINT:
case SIGABRT:
case SIGILL:
case SIGSEGV:
init_term_object->finish();
std::fflush (stderr);
std::fflush (stdout);
2019-09-29 22:28:58 +02:00
std::cerr << "\nProgram stopped: signal "
<< signum
<< " (" << strsignal(signum) << ")" << std::endl;
std::terminate();
2015-05-23 13:35:12 +02:00
}
}
// FTerm non-member functions
//----------------------------------------------------------------------
uInt env2uint (const char* env)
{
FString str(getenv(env));
if ( str.isEmpty() )
return 0;
try
{
return str.toUInt();
}
2018-11-25 04:48:57 +01:00
catch (const std::exception&)
{
return 0;
}
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
wchar_t cp437_to_unicode (uChar c)
{
constexpr std::size_t CP437 = 0;
constexpr std::size_t UNICODE = 1;
wchar_t ucs(c);
for (std::size_t i{0}; i <= fc::lastCP437Item; i++)
{
2019-09-29 22:28:58 +02:00
if ( fc::cp437_ucs[i][CP437] == c ) // found
{
2019-09-29 22:28:58 +02:00
ucs = fc::cp437_ucs[i][UNICODE];
break;
}
}
return ucs;
}
//----------------------------------------------------------------------
uChar unicode_to_cp437 (wchar_t ucs)
{
constexpr std::size_t CP437 = 0;
constexpr std::size_t UNICODE = 1;
uChar c{'?'};
for (std::size_t i{0}; i <= fc::lastCP437Item; i++)
{
2019-09-29 22:28:58 +02:00
if ( fc::cp437_ucs[i][UNICODE] == ucs ) // found
{
2019-09-29 22:28:58 +02:00
c = uChar(fc::cp437_ucs[i][CP437]);
break;
}
}
return c;
}
//----------------------------------------------------------------------
FString getFullWidth (const FString& str)
{
// Converts half-width to full-width characters
FString s(str);
constexpr std::size_t HALF = 0;
constexpr std::size_t FULL = 1;
for (auto&& c : s)
{
if ( c > L'\x20' && c < L'\x7f' ) // half-width ASCII
{
c += 0xfee0;
}
else for (std::size_t i{0}; i <= fc::lastHalfWidthItem; i++)
{
if ( fc::halfWidth_fullWidth[i][HALF] == c ) // found
{
c = fc::halfWidth_fullWidth[i][FULL];
}
}
}
return s;
}
//----------------------------------------------------------------------
FString getHalfWidth (const FString& str)
{
// Converts full-width to half-width characters
FString s(str);
constexpr std::size_t HALF = 0;
constexpr std::size_t FULL = 1;
for (auto&& c : s)
{
if ( c > L'\xff00' && c < L'\xff5f' ) // full-width ASCII
{
c -= 0xfee0;
}
else for (std::size_t i{0}; i <= fc::lastHalfWidthItem; i++)
{
if ( fc::halfWidth_fullWidth[i][FULL] == c ) // found
{
c = fc::halfWidth_fullWidth[i][HALF];
}
}
}
return s;
}
//----------------------------------------------------------------------
std::size_t getColumnWidthToLength ( const FString& str
, std::size_t col_len )
{
std::size_t column_width{0}, length{0};
for (auto&& ch : str)
{
if ( column_width < col_len )
{
column_width += getColumnWidth(ch);
length++;
}
}
return length;
}
//----------------------------------------------------------------------
FString getColumnSubString ( const FString& str
, std::size_t col_pos, std::size_t col_len )
{
FString s(str);
std::size_t col_first{1}, col_num{0}, first{1}, num{0};
if ( col_len == 0 || s.isEmpty() )
return FString(L"");
if ( col_pos == 0 )
col_pos = 1;
for (auto&& ch : s)
{
std::size_t width = getColumnWidth(ch);
if ( col_first < col_pos )
{
if ( col_first + width <= col_pos )
{
col_first += width;
first++;
}
else
{
ch = fc::SingleLeftAngleQuotationMark; //
num = col_num = 1;
col_pos = col_first;
}
}
else
{
if ( col_num + width <= col_len )
{
col_num += width;
num++;
}
else if ( col_num < col_len )
{
ch = fc::SingleRightAngleQuotationMark; //
num++;
break;
}
}
}
if ( col_first < col_pos ) // String length < col_pos
return FString(L"");
return s.mid(first, num);
}
//----------------------------------------------------------------------
std::size_t getColumnWidth (const FString& s, std::size_t pos)
{
if ( s.isEmpty() )
return 0;
std::size_t column_width{0};
auto length = s.getLength();
if ( pos > length )
pos = length;
for (std::size_t i{0}; i < pos; i++)
column_width += getColumnWidth(s[i]);
return column_width;
}
//----------------------------------------------------------------------
std::size_t getColumnWidth (const FString& s)
{
if ( s.isEmpty() )
return 0;
const wchar_t* str = s.wc_str();
size_t len = std::wcslen(str);
int column_width = wcswidth (str, len);
return ( column_width == -1 ) ? 0 : std::size_t(column_width);
}
//----------------------------------------------------------------------
std::size_t getColumnWidth (const wchar_t wchar)
{
int column_width = wcwidth (wchar);
return ( column_width == -1 ) ? 0 : std::size_t(column_width);
}
//----------------------------------------------------------------------
std::size_t getColumnWidth (charData& term_char)
{
int column_width = wcwidth (term_char.code);
std::size_t char_width = ( column_width == -1 ) ? 0 : std::size_t(column_width);
if ( char_width == 2 && FTerm::getEncoding() != fc::UTF8 )
{
term_char.code = '.';
term_char.attr.bit.char_width = 1;
}
else
term_char.attr.bit.char_width = char_width & 0x03;
return char_width;
}
//----------------------------------------------------------------------
std::size_t getColumnWidth (const FTermBuffer& termbuffer)
{
std::size_t column_width{0};
for (auto&& tc : termbuffer)
column_width += tc.attr.bit.char_width;
return column_width;
}
} // namespace finalcut