1 /* 2 * Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "CliContext.h" 8 9 #include <AutoLocker.h> 10 11 #include "UserInterface.h" 12 13 14 // NOTE: This is a simple work-around for EditLine not having any kind of user 15 // data field. Hence in _GetPrompt() we don't have access to the context object. 16 // ATM only one CLI is possible in Debugger, so a static variable works well 17 // enough. Should that ever change, we would need a thread-safe 18 // EditLine* -> CliContext* map. 19 static CliContext* sCurrentContext; 20 21 22 CliContext::CliContext() 23 : 24 fLock("CliContext"), 25 fTeam(NULL), 26 fListener(NULL), 27 fEditLine(NULL), 28 fHistory(NULL), 29 fPrompt(NULL), 30 fBlockingSemaphore(-1), 31 fInputLoopWaiting(false), 32 fTerminating(false) 33 { 34 sCurrentContext = this; 35 } 36 37 CliContext::~CliContext() 38 { 39 Cleanup(); 40 sCurrentContext = NULL; 41 } 42 43 44 status_t 45 CliContext::Init(Team* team, UserInterfaceListener* listener) 46 { 47 fTeam = team; 48 fListener = listener; 49 50 status_t error = fLock.InitCheck(); 51 if (error != B_OK) 52 return error; 53 54 fBlockingSemaphore = create_sem(0, "CliContext block"); 55 if (fBlockingSemaphore < 0) 56 return fBlockingSemaphore; 57 58 fEditLine = el_init("Debugger", stdin, stdout, stderr); 59 if (fEditLine == NULL) 60 return B_ERROR; 61 62 fHistory = history_init(); 63 if (fHistory == NULL) 64 return B_ERROR; 65 66 HistEvent historyEvent; 67 history(fHistory, &historyEvent, H_SETSIZE, 100); 68 69 el_set(fEditLine, EL_HIST, &history, fHistory); 70 el_set(fEditLine, EL_EDITOR, "emacs"); 71 el_set(fEditLine, EL_PROMPT, &_GetPrompt); 72 73 return B_OK; 74 } 75 76 77 void 78 CliContext::Cleanup() 79 { 80 Terminating(); 81 82 if (fEditLine != NULL) { 83 el_end(fEditLine); 84 fEditLine = NULL; 85 } 86 87 if (fHistory != NULL) { 88 history_end(fHistory); 89 fHistory = NULL; 90 } 91 } 92 93 94 void 95 CliContext::Terminating() 96 { 97 AutoLocker<BLocker> locker(fLock); 98 99 fTerminating = true; 100 101 if (fBlockingSemaphore >= 0) { 102 delete_sem(fBlockingSemaphore); 103 fBlockingSemaphore = -1; 104 } 105 106 fInputLoopWaiting = false; 107 108 // TODO: Signal the input loop, should it be in PromptUser()! 109 } 110 111 112 const char* 113 CliContext::PromptUser(const char* prompt) 114 { 115 fPrompt = prompt; 116 117 int count; 118 const char* line = el_gets(fEditLine, &count); 119 120 fPrompt = NULL; 121 122 return line; 123 } 124 125 126 void 127 CliContext::AddLineToInputHistory(const char* line) 128 { 129 HistEvent historyEvent; 130 history(fHistory, &historyEvent, H_ENTER, line); 131 } 132 133 134 void 135 CliContext::QuitSession(bool killTeam) 136 { 137 AutoLocker<BLocker> locker(fLock); 138 139 sem_id blockingSemaphore = fBlockingSemaphore; 140 fInputLoopWaiting = true; 141 142 locker.Unlock(); 143 144 fListener->UserInterfaceQuitRequested( 145 killTeam 146 ? UserInterfaceListener::QUIT_OPTION_ASK_KILL_TEAM 147 : UserInterfaceListener::QUIT_OPTION_ASK_RESUME_TEAM); 148 149 while (acquire_sem(blockingSemaphore) == B_INTERRUPTED) { 150 } 151 } 152 153 154 void 155 CliContext::WaitForThreadOrUser() 156 { 157 // TODO:... 158 } 159 160 161 /*static*/ const char* 162 CliContext::_GetPrompt(EditLine* editLine) 163 { 164 return sCurrentContext != NULL ? sCurrentContext->fPrompt : NULL; 165 } 166