Chandler Carruth 2946cd7010 Update the file headers across all of the LLVM projects in the monorepo
to reflect the new license.

We understand that people may be surprised that we're moving the header
entirely to discuss the new license. We checked this carefully with the
Foundation's lawyer and we believe this is the correct approach.

Essentially, all code in the project is now made available by the LLVM
project under our new license, so you will see that the license headers
include that license only. Some of our contributors have contributed
code under our old license, and accordingly, we have retained a copy of
our old license notice in the top-level files in each project and
repository.

llvm-svn: 351636
2019-01-19 08:50:56 +00:00

263 lines
8.2 KiB
C++

//===-- Terminal.cpp --------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "lldb/Host/Terminal.h"
#include "lldb/Host/Config.h"
#include "lldb/Host/PosixApi.h"
#include "llvm/ADT/STLExtras.h"
#include <fcntl.h>
#include <signal.h>
#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
#include <termios.h>
#endif
using namespace lldb_private;
bool Terminal::IsATerminal() const { return m_fd >= 0 && ::isatty(m_fd); }
bool Terminal::SetEcho(bool enabled) {
if (FileDescriptorIsValid()) {
#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
if (IsATerminal()) {
struct termios fd_termios;
if (::tcgetattr(m_fd, &fd_termios) == 0) {
bool set_corectly = false;
if (enabled) {
if (fd_termios.c_lflag & ECHO)
set_corectly = true;
else
fd_termios.c_lflag |= ECHO;
} else {
if (fd_termios.c_lflag & ECHO)
fd_termios.c_lflag &= ~ECHO;
else
set_corectly = true;
}
if (set_corectly)
return true;
return ::tcsetattr(m_fd, TCSANOW, &fd_termios) == 0;
}
}
#endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
}
return false;
}
bool Terminal::SetCanonical(bool enabled) {
if (FileDescriptorIsValid()) {
#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
if (IsATerminal()) {
struct termios fd_termios;
if (::tcgetattr(m_fd, &fd_termios) == 0) {
bool set_corectly = false;
if (enabled) {
if (fd_termios.c_lflag & ICANON)
set_corectly = true;
else
fd_termios.c_lflag |= ICANON;
} else {
if (fd_termios.c_lflag & ICANON)
fd_termios.c_lflag &= ~ICANON;
else
set_corectly = true;
}
if (set_corectly)
return true;
return ::tcsetattr(m_fd, TCSANOW, &fd_termios) == 0;
}
}
#endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
}
return false;
}
//----------------------------------------------------------------------
// Default constructor
//----------------------------------------------------------------------
TerminalState::TerminalState()
: m_tty(), m_tflags(-1),
#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
m_termios_ap(),
#endif
m_process_group(-1) {
}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
TerminalState::~TerminalState() {}
void TerminalState::Clear() {
m_tty.Clear();
m_tflags = -1;
#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
m_termios_ap.reset();
#endif
m_process_group = -1;
}
//----------------------------------------------------------------------
// Save the current state of the TTY for the file descriptor "fd" and if
// "save_process_group" is true, attempt to save the process group info for the
// TTY.
//----------------------------------------------------------------------
bool TerminalState::Save(int fd, bool save_process_group) {
m_tty.SetFileDescriptor(fd);
if (m_tty.IsATerminal()) {
#ifndef LLDB_DISABLE_POSIX
m_tflags = ::fcntl(fd, F_GETFL, 0);
#endif
#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
if (m_termios_ap.get() == NULL)
m_termios_ap.reset(new struct termios);
int err = ::tcgetattr(fd, m_termios_ap.get());
if (err != 0)
m_termios_ap.reset();
#endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
#ifndef LLDB_DISABLE_POSIX
if (save_process_group)
m_process_group = ::tcgetpgrp(0);
else
m_process_group = -1;
#endif
} else {
m_tty.Clear();
m_tflags = -1;
#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
m_termios_ap.reset();
#endif
m_process_group = -1;
}
return IsValid();
}
//----------------------------------------------------------------------
// Restore the state of the TTY using the cached values from a previous call to
// Save().
//----------------------------------------------------------------------
bool TerminalState::Restore() const {
#ifndef LLDB_DISABLE_POSIX
if (IsValid()) {
const int fd = m_tty.GetFileDescriptor();
if (TFlagsIsValid())
fcntl(fd, F_SETFL, m_tflags);
#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
if (TTYStateIsValid())
tcsetattr(fd, TCSANOW, m_termios_ap.get());
#endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
if (ProcessGroupIsValid()) {
// Save the original signal handler.
void (*saved_sigttou_callback)(int) = NULL;
saved_sigttou_callback = (void (*)(int))signal(SIGTTOU, SIG_IGN);
// Set the process group
tcsetpgrp(fd, m_process_group);
// Restore the original signal handler.
signal(SIGTTOU, saved_sigttou_callback);
}
return true;
}
#endif
return false;
}
//----------------------------------------------------------------------
// Returns true if this object has valid saved TTY state settings that can be
// used to restore a previous state.
//----------------------------------------------------------------------
bool TerminalState::IsValid() const {
return m_tty.FileDescriptorIsValid() &&
(TFlagsIsValid() || TTYStateIsValid());
}
//----------------------------------------------------------------------
// Returns true if m_tflags is valid
//----------------------------------------------------------------------
bool TerminalState::TFlagsIsValid() const { return m_tflags != -1; }
//----------------------------------------------------------------------
// Returns true if m_ttystate is valid
//----------------------------------------------------------------------
bool TerminalState::TTYStateIsValid() const {
#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
return m_termios_ap.get() != 0;
#else
return false;
#endif
}
//----------------------------------------------------------------------
// Returns true if m_process_group is valid
//----------------------------------------------------------------------
bool TerminalState::ProcessGroupIsValid() const {
return static_cast<int32_t>(m_process_group) != -1;
}
//------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------
TerminalStateSwitcher::TerminalStateSwitcher() : m_currentState(UINT32_MAX) {}
//------------------------------------------------------------------
// Destructor
//------------------------------------------------------------------
TerminalStateSwitcher::~TerminalStateSwitcher() {}
//------------------------------------------------------------------
// Returns the number of states that this switcher contains
//------------------------------------------------------------------
uint32_t TerminalStateSwitcher::GetNumberOfStates() const {
return llvm::array_lengthof(m_ttystates);
}
//------------------------------------------------------------------
// Restore the state at index "idx".
//
// Returns true if the restore was successful, false otherwise.
//------------------------------------------------------------------
bool TerminalStateSwitcher::Restore(uint32_t idx) const {
const uint32_t num_states = GetNumberOfStates();
if (idx >= num_states)
return false;
// See if we already are in this state?
if (m_currentState < num_states && (idx == m_currentState) &&
m_ttystates[idx].IsValid())
return true;
// Set the state to match the index passed in and only update the current
// state if there are no errors.
if (m_ttystates[idx].Restore()) {
m_currentState = idx;
return true;
}
// We failed to set the state. The tty state was invalid or not initialized.
return false;
}
//------------------------------------------------------------------
// Save the state at index "idx" for file descriptor "fd" and save the process
// group if requested.
//
// Returns true if the restore was successful, false otherwise.
//------------------------------------------------------------------
bool TerminalStateSwitcher::Save(uint32_t idx, int fd,
bool save_process_group) {
const uint32_t num_states = GetNumberOfStates();
if (idx < num_states)
return m_ttystates[idx].Save(fd, save_process_group);
return false;
}