xref: /haiku/src/system/boot/platform/openfirmware/console.cpp (revision d3d8b26997fac34a84981e6d2b649521de2cc45a)
1 /*
2  * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <SupportDefs.h>
8 #include <string.h>
9 #include <platform/openfirmware/openfirmware.h>
10 #include <util/kernel_cpp.h>
11 
12 #include "Handle.h"
13 #include "console.h"
14 
15 
16 class ConsoleHandle : public Handle {
17 	public:
18 		ConsoleHandle();
19 
20 		virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer,
21 			size_t bufferSize);
22 		virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer,
23 			size_t bufferSize);
24 };
25 
26 class InputConsoleHandle : public ConsoleHandle {
27 	public:
28 		InputConsoleHandle();
29 
30 		virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer,
31 			size_t bufferSize);
32 
33 		void PutChar(char c);
34 		void PutChars(const char *buffer, int count);
35 		char GetChar();
36 
37 	private:
38 		enum { BUFFER_SIZE = 32 };
39 
40 		char	fBuffer[BUFFER_SIZE];
41 		int		fStart;
42 		int		fCount;
43 };
44 
45 
46 static InputConsoleHandle sInput;
47 static ConsoleHandle sOutput;
48 FILE *stdin, *stdout, *stderr;
49 
50 
51 ConsoleHandle::ConsoleHandle()
52 	: Handle()
53 {
54 }
55 
56 
57 ssize_t
58 ConsoleHandle::ReadAt(void */*cookie*/, off_t /*pos*/, void *buffer,
59 	size_t bufferSize)
60 {
61 	// don't seek in character devices
62 	return of_read(fHandle, buffer, bufferSize);
63 }
64 
65 
66 ssize_t
67 ConsoleHandle::WriteAt(void */*cookie*/, off_t /*pos*/, const void *buffer,
68 	size_t bufferSize)
69 {
70 	const char *string = (const char *)buffer;
71 
72 	// be nice to our audience and replace single "\n" with "\r\n"
73 
74 	while (bufferSize > 0) {
75 		bool newLine = false;
76 		size_t length = 0;
77 
78 		for (; length < bufferSize; length++) {
79 			if (string[length] == '\r' && length + 1 < bufferSize) {
80 				length += 2;
81 			} else if (string[length] == '\n') {
82 				newLine = true;
83 				break;
84 			}
85 		}
86 
87 		if (length > 0) {
88 			of_write(fHandle, string, length);
89 			string += length;
90 			bufferSize -= length;
91 		}
92 
93 		if (newLine) {
94 			// this code replaces a single '\n' with '\r\n', so it
95 			// bumps the string/bufferSize only a single character
96 			of_write(fHandle, "\r\n", 2);
97 			string++;
98 			bufferSize--;
99 		}
100 	}
101 
102 	return string - (char *)buffer;
103 }
104 
105 
106 //	#pragma mark -
107 
108 
109 InputConsoleHandle::InputConsoleHandle()
110 	: ConsoleHandle()
111 	, fStart(0)
112 	, fCount(0)
113 {
114 }
115 
116 
117 ssize_t
118 InputConsoleHandle::ReadAt(void */*cookie*/, off_t /*pos*/, void *_buffer,
119 	size_t bufferSize)
120 {
121 	char *buffer = (char*)_buffer;
122 
123 	// copy buffered bytes first
124 	int bytesTotal = 0;
125 	while (bufferSize > 0 && fCount > 0) {
126 		*buffer++ = GetChar();
127 		bytesTotal++;
128 		bufferSize--;
129 	}
130 
131 	// read from console
132 	if (bufferSize > 0) {
133 		ssize_t bytesRead = ConsoleHandle::ReadAt(NULL, 0, buffer, bufferSize);
134 		if (bytesRead < 0)
135 			return bytesRead;
136 		bytesTotal += bytesRead;
137 	}
138 
139 	return bytesTotal;
140 }
141 
142 
143 void
144 InputConsoleHandle::PutChar(char c)
145 {
146 	if (fCount >= BUFFER_SIZE)
147 		return;
148 
149 	int pos = (fStart + fCount) % BUFFER_SIZE;
150 	fBuffer[pos] = c;
151 	fCount++;
152 }
153 
154 
155 void
156 InputConsoleHandle::PutChars(const char *buffer, int count)
157 {
158 	for (int i = 0; i < count; i++)
159 		PutChar(buffer[i]);
160 }
161 
162 
163 char
164 InputConsoleHandle::GetChar()
165 {
166 	if (fCount == 0)
167 		return 0;
168 
169 	fCount--;
170 	char c = fBuffer[fStart];
171 	fStart = (fStart + 1) % BUFFER_SIZE;
172 	return c;
173 }
174 
175 
176 //	#pragma mark -
177 
178 
179 status_t
180 console_init(void)
181 {
182 	int input, output;
183 	if (of_getprop(gChosen, "stdin", &input, sizeof(int)) == OF_FAILED)
184 		return B_ERROR;
185 	if (of_getprop(gChosen, "stdout", &output, sizeof(int)) == OF_FAILED)
186 		return B_ERROR;
187 
188 	sInput.SetHandle(input);
189 	sOutput.SetHandle(output);
190 
191 	// now that we're initialized, enable stdio functionality
192 	stdin = (FILE *)&sInput;
193 	stdout = stderr = (FILE *)&sOutput;
194 
195 	return B_OK;
196 }
197 
198 
199 // #pragma mark -
200 
201 
202 void
203 console_clear_screen(void)
204 {
205 	of_interpret("erase-screen", 0, 0);
206 }
207 
208 
209 int32
210 console_width(void)
211 {
212 	int columnCount;
213 	if (of_interpret("#columns", 0, 1, &columnCount) == OF_FAILED)
214 		return 0;
215 	return columnCount;
216 }
217 
218 
219 int32
220 console_height(void)
221 {
222 	int lineCount;
223 	if (of_interpret("#lines", 0, 1, &lineCount) == OF_FAILED)
224 		return 0;
225 	return lineCount;
226 }
227 
228 
229 void
230 console_set_cursor(int32 x, int32 y)
231 {
232 	// Note: We toggle the cursor temporarily to prevent a cursor artifact at
233 	// at the old location.
234 	of_interpret("toggle-cursor"
235 		" to line#"
236 		" to column#"
237 		" toggle-cursor",
238 		2, 0, y, x);
239 
240 }
241 
242 
243 static int
244 translate_color(int32 color)
245 {
246 	/*
247 			r	g	b
248 		0:	0	0	0		// black
249 		1:	0	0	aa		// dark blue
250 		2:	0	aa	0		// dark green
251 		3:	0	aa	aa		// cyan
252 		4:	aa	0	0		// dark red
253 		5:	aa	0	aa		// purple
254 		6:	aa	55	0		// brown
255 		7:	aa	aa	aa		// light gray
256 		8:	55	55	55		// dark gray
257 		9:	55	55	ff		// light blue
258 		a:	55	ff	55		// light green
259 		b:	55	ff	ff		// light cyan
260 		c:	ff	55	55		// light red
261 		d:	ff	55	ff		// magenta
262 		e:	ff	ff	55		// yellow
263 		f:	ff	ff	ff		// white
264 	*/
265 	if (color >= 0 && color < 16)
266 		return color;
267 	return 0;
268 }
269 
270 
271 void
272 console_set_color(int32 foreground, int32 background)
273 {
274 	// Note: Toggling the cursor doesn't seem to help. We still get cursor
275 	// artifacts.
276 	of_interpret("toggle-cursor"
277 		" to foreground-color"
278 		" to background-color"
279 		" toggle-cursor",
280 		2, 0, translate_color(foreground), translate_color(background));
281 }
282 
283 
284 int
285 console_wait_for_key(void)
286 {
287 	// wait for a key
288 	char buffer[3];
289 	ssize_t bytesRead;
290 	do {
291 		bytesRead = sInput.ReadAt(NULL, 0, buffer, 3);
292 		if (bytesRead < 0)
293 			return 0;
294 	} while (bytesRead == 0);
295 
296 	// translate the ESC sequences for cursor keys
297 	if (bytesRead == 3 && buffer[0] == 27 && buffer [1] == 91) {
298 		switch (buffer[2]) {
299 			case 65:
300 				return TEXT_CONSOLE_KEY_UP;
301 			case 66:
302 				return TEXT_CONSOLE_KEY_DOWN;
303 			case 67:
304 				return TEXT_CONSOLE_KEY_RIGHT;
305 			case 68:
306 				return TEXT_CONSOLE_KEY_LEFT;
307 // TODO: Translate the codes for the following keys. Unfortunately my OF just
308 // returns a '\0' character. :-/
309 // 			TEXT_CONSOLE_KEY_PAGE_UP,
310 // 			TEXT_CONSOLE_KEY_PAGE_DOWN,
311 // 			TEXT_CONSOLE_KEY_HOME,
312 // 			TEXT_CONSOLE_KEY_END,
313 
314 			default:
315 				break;
316 		}
317 	}
318 
319 	// put back unread chars
320 	if (bytesRead > 1)
321 		sInput.PutChars(buffer + 1, bytesRead - 1);
322 
323 	return buffer[0];
324 }
325 
326