Skip to content

Commit 25feddb

Browse files
committed
Signal_handler to clean the terminal
1 parent 808d1be commit 25feddb

10 files changed

+250
-23
lines changed

cpp-terminal/iostream_initializer.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
#include <cstddef>
1919
#include <iostream>
20-
2120
std::size_t Term::IOStreamInitializer::m_counter{0};
2221

2322
Term::IOStreamInitializer::IOStreamInitializer() noexcept

cpp-terminal/private/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ target_sources(cpp-terminal-private INTERFACE
2222
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/env.cpp>
2323
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/blocking_queue.cpp>
2424
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/sigwinch.cpp>
25+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/signals.cpp>
2526
)
2627
target_link_libraries(cpp-terminal-private INTERFACE Warnings::Warnings Threads::Threads)
2728
target_compile_options(cpp-terminal-private INTERFACE $<$<CXX_COMPILER_ID:MSVC>:/utf-8>)

cpp-terminal/private/signals.cpp

+159
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/*
2+
* cpp-terminal
3+
* C++ library for writing multi-platform terminal applications.
4+
*
5+
* SPDX-FileCopyrightText: 2019-2024 cpp-terminal
6+
*
7+
* SPDX-License-Identifier: MIT
8+
*/
9+
10+
#include "cpp-terminal/private/signals.hpp"
11+
12+
#include "cpp-terminal/terminal.hpp"
13+
14+
#include <algorithm>
15+
#include <csignal>
16+
17+
#ifndef NSIG
18+
#define NSIG (_SIGMAX + 1) /* For QNX */
19+
#endif
20+
21+
const std::size_t Term::Private::Signals::m_signals_number{NSIG - 1};
22+
23+
void Term::Private::Signals::setHandler(const sighandler_t& handler) noexcept
24+
{
25+
for(std::size_t signal = 0; signal != m_signals_number; ++signal) { sighandler_t hand = std::signal(signal, handler); }
26+
}
27+
28+
Term::Private::Signals::Signals(std::vector<sighandler_t>& m_han) noexcept
29+
{
30+
const static std::vector<int> ignore{
31+
#if defined(SIGCONT)
32+
SIGCONT,
33+
#endif
34+
#if defined(SIGSTOP)
35+
SIGSTOP,
36+
#endif
37+
#if defined(SIGTSTP)
38+
SIGTSTP,
39+
#endif
40+
#if defined(SIGTTIN)
41+
SIGTTIN,
42+
#endif
43+
#if defined(SIGTTOU)
44+
SIGTTOU,
45+
#endif
46+
};
47+
m_han.reserve(m_signals_number);
48+
for(std::size_t signal = 0; signal != m_signals_number; ++signal)
49+
{
50+
//if(std::find(ignore.begin(),ignore.end(),signal)==ignore.end())
51+
//{
52+
sighandler_t old = std::signal(signal, SIG_DFL);
53+
//sighandler_t dumb=std::signal(signal, old);
54+
m_han.push_back(old);
55+
//}
56+
//else
57+
//{
58+
// std::signal(signal, SIG_IGN);
59+
// m_han.push_back(std::signal(signal, SIG_IGN));
60+
// }
61+
}
62+
}
63+
64+
void Term::Private::Signals::reset_and_raise(int sign, std::vector<sighandler_t>& m_han, Term::Terminal& term) noexcept
65+
{
66+
const static std::vector<int> termin{
67+
#if defined(SIGHUP)
68+
SIGHUP,
69+
#endif
70+
#if defined(SIGHUP)
71+
SIGINT,
72+
#endif
73+
#if defined(SIGQUIT)
74+
SIGQUIT,
75+
#endif
76+
#if defined(SIGQUIT)
77+
SIGILL,
78+
#endif
79+
#if defined(SIGTRAP)
80+
SIGTRAP,
81+
#endif
82+
#if defined(SIGTRAP)
83+
SIGABRT,
84+
#endif
85+
#if defined(SIGIOT)
86+
SIGIOT,
87+
#endif
88+
#if defined(SIGBUS)
89+
SIGBUS,
90+
#endif
91+
#if defined(SIGBUS)
92+
SIGFPE,
93+
#endif
94+
#if defined(SIGKILL)
95+
SIGKILL,
96+
#endif
97+
#if defined(SIGUSR1)
98+
SIGUSR1,
99+
#endif
100+
#if defined(SIGSEGV)
101+
SIGSEGV,
102+
#endif
103+
#if defined(SIGUSR2)
104+
SIGUSR2,
105+
#endif
106+
#if defined(SIGUSR2)
107+
SIGPIPE,
108+
#endif
109+
#if defined(SIGALRM)
110+
SIGALRM,
111+
#endif
112+
#if defined(SIGSTKFLT)
113+
SIGSTKFLT,
114+
#endif
115+
#if defined(SIGCONT)
116+
SIGCONT,
117+
#endif
118+
#if defined(SIGXCPU)
119+
SIGXCPU,
120+
#endif
121+
#if defined(SIGXFSZ)
122+
SIGXFSZ,
123+
#endif
124+
#if defined(SIGVTALRM)
125+
SIGVTALRM,
126+
#endif
127+
#if defined(SIGPROF)
128+
SIGPROF,
129+
#endif
130+
#if defined(SIGPROF)
131+
SIGIO,
132+
#endif
133+
#if defined(SIGPOLL)
134+
SIGPOLL,
135+
#endif
136+
#if defined(SIGPWR)
137+
SIGPWR,
138+
#endif
139+
#if defined(SIGSYS)
140+
SIGSYS,
141+
#endif
142+
#if defined(SIGUNUSED)
143+
SIGUNUSED,
144+
#endif
145+
#if defined(SIGUNUSED)
146+
SIGUNUSED,
147+
#endif
148+
#if defined(SIGTERM)
149+
SIGTERM
150+
#endif
151+
};
152+
if(std::find(termin.begin(), termin.end(), sign) != termin.end())
153+
{
154+
sighandler_t old = std::signal(sign, m_han[sign]);
155+
old = std::signal(sign, m_han[sign]);
156+
term.clean();
157+
std::raise(sign);
158+
}
159+
}

cpp-terminal/private/signals.hpp

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* cpp-terminal
3+
* C++ library for writing multi-platform terminal applications.
4+
*
5+
* SPDX-FileCopyrightText: 2019-2024 cpp-terminal
6+
*
7+
* SPDX-License-Identifier: MIT
8+
*/
9+
10+
#pragma once
11+
#include <cstddef>
12+
#include <vector>
13+
14+
using sighandler_t = void (*)(int);
15+
16+
namespace Term
17+
{
18+
class Terminal;
19+
namespace Private
20+
{
21+
class Signals
22+
{
23+
public:
24+
Signals(std::vector<sighandler_t>& m_han) noexcept;
25+
~Signals() noexcept {}
26+
void setHandler(const sighandler_t& handler) noexcept;
27+
static void reset_and_raise(int sign, std::vector<sighandler_t>& m_han, Term::Terminal&) noexcept;
28+
29+
private:
30+
const static std::size_t m_signals_number;
31+
};
32+
} // namespace Private
33+
} // namespace Term

cpp-terminal/private/terminal_impl.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "cpp-terminal/private/env.hpp"
1212
#include "cpp-terminal/private/exception.hpp"
1313
#include "cpp-terminal/private/file.hpp"
14+
//#include "cpp-terminal/private/signals.hpp"
1415
#include "cpp-terminal/private/sigwinch.hpp"
1516
#include "cpp-terminal/terminal.hpp"
1617

@@ -224,7 +225,7 @@ void Term::Terminal::setMode() const
224225
unsetFocusEvents();
225226
}
226227
if(m_options.has(Option::NoSignalKeys)) { send.c_lflag &= ~static_cast<std::size_t>(ISIG); } //FIXME need others flags !
227-
else if(m_options.has(Option::SignalKeys)) { send.c_lflag |= ISIG; }
228+
if(m_options.has(Option::SignalKeys)) { send.c_lflag |= ISIG; }
228229
Term::Private::Errno().check_if(tcsetattr(Private::out.fd(), TCSAFLUSH, &send) == -1).throw_exception("tcsetattr(Private::out.fd(), TCSAFLUSH, &send)");
229230
}
230231
#endif

cpp-terminal/terminal_impl.cpp

+10-5
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,20 @@ catch(...)
3131
ExceptionHandler(Private::ExceptionDestination::StdErr);
3232
}
3333

34-
Term::Terminal::~Terminal() noexcept
35-
try
34+
void Term::Terminal::clean()
3635
{
37-
if(getOptions().has(Option::ClearScreen)) { Term::Private::out.write(clear_buffer() + style(Style::Reset) + cursor_move(1, 1) + screen_load()); }
36+
unsetFocusEvents();
37+
unsetMouseEvents();
3838
if(getOptions().has(Option::NoCursor)) { Term::Private::out.write(cursor_on()); }
39+
if(getOptions().has(Option::ClearScreen)) { Term::Private::out.write(clear_buffer() + style(Style::Reset) + cursor_move(1, 1) + screen_load()); }
3940
set_unset_utf8();
4041
store_and_restore();
41-
unsetFocusEvents();
42-
unsetMouseEvents();
42+
}
43+
44+
Term::Terminal::~Terminal() noexcept
45+
try
46+
{
47+
clean();
4348
}
4449
catch(...)
4550
{

cpp-terminal/terminal_impl.hpp

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#pragma once
1111

1212
#include "cpp-terminal/options.hpp"
13+
#include "cpp-terminal/private/signals.hpp"
1314
#include "cpp-terminal/terminal_initializer.hpp"
1415

1516
#include <cstddef>
@@ -20,6 +21,7 @@ namespace Term
2021
class Terminal
2122
{
2223
public:
24+
friend class Private::Signals;
2325
~Terminal() noexcept;
2426
Terminal() noexcept;
2527
Terminal(const Terminal&) = delete;
@@ -55,6 +57,7 @@ class Terminal
5557

5658
static void set_unset_utf8();
5759
Term::Options m_options;
60+
void clean();
5861
};
5962

6063
} // namespace Term

cpp-terminal/terminal_initializer.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "cpp-terminal/private/exception.hpp"
1313
#include "cpp-terminal/private/file_initializer.hpp"
14+
#include "cpp-terminal/private/signals.hpp"
1415
#include "cpp-terminal/terminal.hpp"
1516

1617
#include <new>
@@ -23,7 +24,11 @@ try
2324
if(0 == m_counter)
2425
{
2526
static const Private::FileInitializer files_init;
27+
static std::vector<sighandler_t> m_handlers;
2628
new(&Term::terminal) Terminal();
29+
static Term::Private::Signals signals(m_handlers);
30+
sighandler_t handler = [](int signum) { Term::Private::Signals::reset_and_raise(signum, m_handlers, Term::terminal); };
31+
signals.setHandler(handler);
2732
}
2833
++m_counter;
2934
}

examples/menu.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "cpp-terminal/input.hpp"
1313
#include "cpp-terminal/iostream.hpp"
1414
#include "cpp-terminal/key.hpp"
15+
#include "cpp-terminal/options.hpp"
1516
#include "cpp-terminal/screen.hpp"
1617
#include "cpp-terminal/style.hpp"
1718
#include "cpp-terminal/terminal.hpp"
@@ -93,7 +94,7 @@ int main()
9394
try
9495
{
9596
// check if the terminal is capable of handling input
96-
Term::terminal.setOptions(Term::Option::ClearScreen, Term::Option::NoSignalKeys, Term::Option::NoCursor, Term::Option::Raw);
97+
Term::terminal.setOptions(Term::Option::Raw, Term::Option::NoSignalKeys, Term::Option::ClearScreen, Term::Option::NoCursor);
9798
if(!Term::is_stdin_a_tty()) { throw Term::Exception("The terminal is not attached to a TTY and therefore can't catch user input. Exiting..."); }
9899
Term::Screen term_size = Term::screen_size();
99100
std::size_t pos{5};
@@ -141,8 +142,7 @@ int main()
141142
need_to_render = true;
142143
break;
143144
case Term::Key::q:
144-
case Term::Key::Esc:
145-
case Term::Key::Ctrl_C: on = false;
145+
case Term::Key::Esc: on = false; break;
146146
default: break;
147147
}
148148
break;

examples/signal.cpp

+34-13
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,46 @@
99
*/
1010

1111
#include "cpp-terminal/iostream.hpp"
12+
#include "cpp-terminal/options.hpp"
1213
#include "cpp-terminal/terminal.hpp"
1314

15+
#include <csignal>
16+
#include <fstream>
1417
#include <iostream>
1518

1619
int main()
1720
{
18-
std::at_quick_exit(
19-
[]()
20-
{
21-
std::cout << "Unhandled exception\n" << std::flush;
22-
//std::abort();
23-
});
24-
std::set_terminate(
25-
[]()
26-
{
27-
std::cout << "Unhandled exception\n" << std::flush;
28-
//std::abort();
29-
});
30-
Term::terminal.setOptions(Term::Option::Raw, Term::Option::SignalKeys);
21+
Term::terminal.setOptions(Term::Option::Raw, Term::Option::NoSignalKeys, Term::Option::ClearScreen);
22+
std::signal(SIGINT,
23+
[](int sig)
24+
{
25+
std::ofstream outfile("cpp_terminal_signal.txt");
26+
outfile << "my text here!" << std::endl;
27+
outfile.close();
28+
std::exit(1);
29+
});
30+
std::cout << "This is printed with std::cout with std::end (1)" << std::endl;
31+
std::clog << "This is printed with std::clog with std::end (2)" << std::endl;
32+
std::cerr << "This is printed with std::cerr with std::end (3)" << std::endl;
33+
34+
Term::cout << "This is printed with Term::cout with std::end (4)" << std::endl;
35+
Term::clog << "This is printed with Term::clog with std::end (5)" << std::endl;
36+
Term::cerr << "This is printed with Term::cerr with std::end (6)" << std::endl;
37+
38+
std::cout << "This is printed with std::cout with flush() (7)\n" << std::flush;
39+
std::clog << "This is printed with std::clog with flush() (8)\n" << std::flush;
40+
std::cerr << "This is printed with std::cerr with flush() (9)\n" << std::flush;
41+
42+
Term::cout << "This is printed with Term::cout with flush() (10)\n" << std::flush;
43+
Term::clog << "This is printed with Term::clog with flush() (11)\n" << std::flush;
44+
Term::cerr << "This is printed with Term::cerr with flush() (12)\n" << std::flush;
45+
46+
std::cout << "This is printed (13) ";
47+
std::cout << "with std::cout (13)";
48+
std::clog << "This is printed (14) ";
49+
std::clog << "with std::clog (14)";
50+
std::cerr << "This is printed (15) ";
51+
std::cerr << "with std::cerr (15)";
3152
while(true) {}
3253
return 0;
3354
}

0 commit comments

Comments
 (0)