21 #include <semaphore.h>
24 #include <readline/readline.h>
30 #include <boost/algorithm/string/trim.hpp>
31 #include <boost/thread.hpp>
34 namespace SourceXtractor {
37 static struct sigaction sigterm_action, sigstop_action, sigcont_action,
sigwich_action;
70 *backup_fd = dup(old_fd);
75 if (pipe(pipe_fds) < 0) {
79 int flags = fcntl(pipe_fds[0], F_GETFL, 0);
80 if (fcntl(pipe_fds[0], F_SETFL, flags | O_NONBLOCK) < 0) {
84 if (dup2(pipe_fds[1], old_fd) < 0) {
106 class Screen :
public boost::noncopyable {
125 rl_catch_signals = 0;
126 rl_deprep_term_function = NULL;
127 rl_prep_term_function = NULL;
132 rl_catch_sigwinch = 0;
136 ::memset(&sigterm_action, 0,
sizeof(sigterm_action));
137 ::memset(&sigstop_action, 0,
sizeof(sigstop_action));
138 ::memset(&sigcont_action, 0,
sizeof(sigcont_action));
143 ::sigaction(SIGINT, &sigterm_action, &
prev_signal[SIGINT]);
144 ::sigaction(SIGTERM, &sigterm_action, &
prev_signal[SIGTERM]);
145 ::sigaction(SIGABRT, &sigterm_action, &
prev_signal[SIGABRT]);
146 ::sigaction(SIGSEGV, &sigterm_action, &
prev_signal[SIGSEGV]);
147 ::sigaction(SIGHUP, &sigterm_action, &
prev_signal[SIGHUP]);
151 ::sigaction(SIGTSTP, &sigstop_action, &
prev_signal[SIGTSTP]);
155 ::sigaction(SIGCONT, &sigcont_action, &
prev_signal[SIGCONT]);
165 m_screen = newterm(
nullptr, outfd, infd);
173 keypad(stdscr, TRUE);
177 use_default_colors();
190 ::sigaction(SIGINT, &
prev_signal[SIGINT],
nullptr);
191 ::sigaction(SIGTERM, &
prev_signal[SIGTERM],
nullptr);
192 ::sigaction(SIGABRT, &
prev_signal[SIGABRT],
nullptr);
193 ::sigaction(SIGSEGV, &
prev_signal[SIGSEGV],
nullptr);
194 ::sigaction(SIGHUP, &
prev_signal[SIGHUP],
nullptr);
195 ::sigaction(SIGCONT, &
prev_signal[SIGCONT],
nullptr);
196 ::sigaction(SIGWINCH, &
prev_signal[SIGWINCH],
nullptr);
237 if (write(
signal_fds[1], &s,
sizeof(s)) ==
sizeof(s)) {
240 #if _POSIX_C_SOURCE >= 200112L
242 clock_gettime(CLOCK_REALTIME, &timeout);
278 sigaction(SIGCONT, &sigcont_action,
nullptr);
279 sigaction(SIGTSTP, &sigstop_action,
nullptr);
286 if (write(
signal_fds[1], &s,
sizeof(s)) < 0) {
326 LogWidget(
int display_height,
int display_width,
int display_y,
int display_x,
short bar_color,
short ind_color)
328 m_scroll(newpad(display_height, 1)),
331 scrollok(
m_pad, TRUE);
345 void write(
const char *data, ssize_t nchars) {
358 waddch(
m_pad, *data);
368 void resize(
int display_height,
int display_width) {
374 if (display_width > getmaxx(
m_pad)) {
375 wresize(
m_pad, getmaxy(
m_pad), display_width);
377 wresize(
m_scroll, display_height, 1);
432 boost::algorithm::trim(term_lines.
back());
450 int displayed_line_offset =
m_active_line - min_selectable_line;
451 float p =
std::max(0.f,
std::min(1.f, displayed_line_offset /
float(max_selectable_line - min_selectable_line)));
455 if (i == scroll_marker_pos)
500 ProgressWidget(
int height,
int width,
int y,
int x,
short done_color,
short progress_color)
501 :
m_window(newwin(height, width, y, x)),
m_started(std::chrono::steady_clock::now()),
548 size_t value_position =
sizeof(
"Elapsed");
550 for (
auto& entry: info) {
551 if (entry.m_label.size() > value_position) {
552 value_position = entry.m_label.size();
558 size_t bar_width = getmaxx(
m_window) - 2 - value_position;
569 for (
auto& entry : info) {
570 drawProgressLine(value_position, bar_width, line, entry.m_label, entry.m_total, entry.m_done);
585 void drawElapsed(
size_t value_position,
const std::chrono::steady_clock::duration& elapsed,
int line)
const {
590 elapsed_str.
fill(
'0');
594 mvwaddstr(
m_window, line, 0,
"Elapsed");
598 line, value_position + 1,
599 elapsed_str.str().c_str()
607 int total,
int done)
const {
615 mvwprintw(
m_window, line, value_position + 1,
"%d", done);
620 float ratio = done /
static_cast<float>(total);
636 mvwaddch(
m_window, line, value_position,
'[');
639 auto bar_content = bar.
str();
640 int completed = bar_content.size() * ratio;
643 waddstr(
m_window, bar_content.substr(0, completed).c_str());
648 waddstr(
m_window, bar_content.substr(completed).c_str());
697 sigaddset(&set, SIGTERM);
698 sigaddset(&set, SIGINT);
699 sigaddset(&set, SIGHUP);
700 pthread_sigmask(SIG_BLOCK, &set,
nullptr);
721 LINES - 1, COLS, 0, 0,
722 screen.
initColor(COLOR_WHITE, COLOR_BLACK), screen.
initColor(COLOR_WHITE, COLOR_WHITE)
727 1, COLS, LINES - 1, 0,
728 screen.
initColor(COLOR_WHITE, COLOR_GREEN), screen.
initColor(COLOR_WHITE, COLOR_BLACK)
732 struct pollfd poll_fds[] = {
735 {STDIN_FILENO, POLLIN, 0},
742 bool exit_loop =
false;
746 if (poll_fds[3].revents & POLLIN) {
748 if (read(
signal_fds[0], &signal_no,
sizeof(signal_no)) > 0 && signal_no == SIGWINCH) {
755 logWidget.write(buf,
snprintf(buf,
sizeof(buf),
"Caught signal %s\n", strsignal(signal_no)));
765 logWidget.resize(LINES - progressWidget.getHeight(), COLS);
770 if (poll_fds[0].revents & POLLIN) {
771 while ((nbytes = read(
m_stderr_pipe, &buf,
sizeof(buf))) > 0) {
772 logWidget.write(buf, nbytes);
775 if (poll_fds[1].revents & POLLIN) {
776 while ((nbytes = read(
m_stdout_pipe, &buf,
sizeof(buf))) > 0) {
777 logWidget.write(buf, nbytes);
782 if (poll_fds[2].revents & POLLIN) {
783 int key = wgetch(stdscr);
784 if (key != KEY_RESIZE) {
785 logWidget.handleKeyPress(key);
798 if (poll(poll_fds, 4, 1000) < 0) {
800 exit_loop = (errno != EINTR);
802 }
while (!exit_loop && !boost::this_thread::interruption_requested());
816 if (new_stderr_fd < 0) {
819 m_stderr = fdopen(new_stderr_fd,
"w");
865 return isatty(STDERR_FILENO);
std::shared_ptr< DependentParameter< std::shared_ptr< EngineParameter > > > x
T generic_category(T...args)
T duration_cast(T...args)
std::shared_ptr< DependentParameter< std::shared_ptr< EngineParameter > > > y