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