Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion include/cling/UserInterface/UserInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,24 @@ namespace cling {
///
class UserInterface {
private:
class TextInputHolder;
std::unique_ptr<TextInputHolder> m_TextInput;
std::unique_ptr<MetaProcessor> m_MetaProcessor;

///\brief Prints cling's startup logo
///
void PrintLogo();
public:
UserInterface(Interpreter& interp);
UserInterface();
~UserInterface();

MetaProcessor* getMetaProcessor() { return m_MetaProcessor.get(); }

///\brief Attach this instance to the given Interpreter.
/// @param[in] Interp - The interpreter to attach to.
///
void attach(Interpreter& Interp);

///\brief Drives the interactive prompt talking to the user.
/// @param[in] nologo - whether to show cling's welcome logo or not
///
Expand Down
62 changes: 36 additions & 26 deletions lib/UserInterface/UserInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,57 +46,67 @@ namespace {
return true;
}
};
}

namespace cling {

///\brief Delays ~TextInput until after ~StreamReader and ~TerminalDisplay
///
class TextInputHolder {
class UserInterface::TextInputHolder {
textinput::StreamReader* m_Reader;
textinput::TerminalDisplay* m_Display;
textinput::TextInput m_Input;

class HistoryFile {
llvm::SmallString<512> Path;

public:
HistoryFile(const char* Env = "CLING_NOHISTORY",
const char* Name = ".cling_history") {
if (getenv(Env)) return;
// History file is $HOME/.cling_history
if (llvm::sys::path::home_directory(Path))
llvm::sys::path::append(Path, Name);
}
const char* c_str() { return Path.empty() ? nullptr : Path.c_str(); }
};

public:
TextInputHolder(llvm::SmallString<512>& Hist)
TextInputHolder(HistoryFile HistFile = HistoryFile())
: m_Reader(textinput::StreamReader::Create()),
m_Display(textinput::TerminalDisplay::Create()),
m_Input(*m_Reader, *m_Display, Hist.empty() ? 0 : Hist.c_str()) {}
m_Input(*m_Reader, *m_Display, HistFile.c_str()) {
}

~TextInputHolder() {
delete m_Reader;
delete m_Display;
}

textinput::TextInput* operator -> () { return &m_Input; }
operator textinput::TextInput& () { return m_Input; }
};
}

namespace cling {

UserInterface::UserInterface(Interpreter& interp) {
m_MetaProcessor.reset(new MetaProcessor(interp, cling::outs()));
UserInterface::UserInterface() {
llvm::install_fatal_error_handler(&CompilationException::throwingHandler);
}

UserInterface::~UserInterface() {}
UserInterface::~UserInterface() { llvm::remove_fatal_error_handler(); }

void UserInterface::attach(Interpreter& Interp) {
m_MetaProcessor.reset(new MetaProcessor(Interp, cling::outs()));
}

void UserInterface::runInteractively(bool nologo /* = false */) {
if (!nologo) {
assert(m_MetaProcessor.get() && "Not attached to an Interpreter.");
if (!nologo)
PrintLogo();
}

llvm::SmallString<512> histfilePath;
if (!getenv("CLING_NOHISTORY")) {
// History file is $HOME/.cling_history
if (llvm::sys::path::home_directory(histfilePath))
llvm::sys::path::append(histfilePath, ".cling_history");
}

TextInputHolder TI(histfilePath);
m_TextInput.reset(new TextInputHolder);
textinput::TextInput& TI = *m_TextInput;

// Inform text input about the code complete consumer
// TextInput owns the TabCompletion.
UITabCompletion* Completion =
new UITabCompletion(m_MetaProcessor->getInterpreter());
TI->SetCompletion(Completion);
TI.SetCompletion(new UITabCompletion(m_MetaProcessor->getInterpreter()));

bool Done = false;
std::string Line;
Expand All @@ -107,9 +117,9 @@ namespace cling {
m_MetaProcessor->getOuts().flush();
{
MetaProcessor::MaybeRedirectOutputRAII RAII(*m_MetaProcessor);
TI->SetPrompt(Prompt.c_str());
Done = TI->ReadInput() == textinput::TextInput::kRREOF;
TI->TakeInput(Line);
TI.SetPrompt(Prompt.c_str());
Done = TI.ReadInput() == textinput::TextInput::kRREOF;
TI.TakeInput(Line);
if (Done && Line.empty())
break;
}
Expand Down
12 changes: 9 additions & 3 deletions lib/Utils/PlatformWin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -788,11 +788,17 @@ void RegisterEHFrames(uintptr_t ImgBs, const EHFrameInfos& Frames, bool Block) {
void DeRegisterEHFrames(uintptr_t ImgBase, const EHFrameInfos& Frames) {
if (Frames.empty())
return;
assert(getImageBaseMap().find(ImgBase) != getImageBaseMap().end());

// Remove the ImageBase from lookup
// There is a chance that DeRegisterEHFrames will have been called without a
// preceeding call to RegisterEHFrames. Rather than tracking such cases,
// just ignore the requests when ImgBase was never registered.
ImageBaseMap& Unwind = getImageBaseMap();
Unwind.erase(Unwind.find(ImgBase));
auto Itr = Unwind.find(ImgBase);
if (Itr == Unwind.end())
return;

// Remove the ImageBase from lookup
Unwind.erase(Itr);

// Unregister all the PRUNTIME_FUNCTIONs
for (auto&& Frame : Frames)
Expand Down
5 changes: 4 additions & 1 deletion tools/driver/cling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ static int checkDiagErrors(clang::CompilerInstance* CI, unsigned* OutErrs = 0) {


int main( int argc, char **argv ) {
// Force the UserInterface to be destroyed last, so any file manipulation,
// pipes, or dups are active for the entire process.
cling::UserInterface Ui;

llvm::llvm_shutdown_obj shutdownTrigger;

Expand Down Expand Up @@ -105,7 +108,7 @@ int main( int argc, char **argv ) {
for (const std::string& Lib : Opts.LibsToLoad)
Interp.loadFile(Lib);

cling::UserInterface Ui(Interp);
Ui.attach(Interp);
// If we are not interactive we're supposed to parse files
if (!Opts.IsInteractive()) {
for (const std::string &Input : Opts.Inputs) {
Expand Down