xref: /haiku/src/apps/debugger/user_interface/cli/CliContext.cpp (revision 0efc5e72dc9502e0121dcd1aca8dfa0f4747d259)
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