Console.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. #include "Console.h"
  2. #include "VGA.h"
  3. #include "IO.h"
  4. #include "kprintf.h"
  5. #include <AK/String.h>
  6. // Bytes output to 0xE9 end up on the Bochs console. It's very handy.
  7. #define CONSOLE_OUT_TO_E9
  8. static Console* s_the;
  9. Console& Console::the()
  10. {
  11. return *s_the;
  12. }
  13. Console::Console()
  14. {
  15. s_the = this;
  16. }
  17. Console::~Console()
  18. {
  19. }
  20. bool Console::hasDataAvailableForRead() const
  21. {
  22. return false;
  23. }
  24. ssize_t Console::read(byte*, size_t)
  25. {
  26. // FIXME: Implement reading from the console.
  27. // Maybe we could use a ring buffer for this device?
  28. return 0;
  29. }
  30. inline bool isParameter(byte ch)
  31. {
  32. return ch >= 0x30 && ch <= 0x3f;
  33. }
  34. inline bool isIntermediate(byte ch)
  35. {
  36. return ch >= 0x20 && ch <= 0x2f;
  37. }
  38. inline bool isFinal(byte ch)
  39. {
  40. return ch >= 0x40 && ch <= 0x7e;
  41. }
  42. unsigned parseUInt(const String& str, bool& ok)
  43. {
  44. unsigned value = 0;
  45. for (size_t i = 0; i < str.length(); ++i) {
  46. if (str[i] < '0' || str[i] > '9') {
  47. ok = false;
  48. return 0;
  49. }
  50. value = value * 10;
  51. value += str[i] - '0';
  52. }
  53. ok = true;
  54. return value;
  55. }
  56. enum class VGAColor : byte {
  57. Black = 0,
  58. Blue,
  59. Green,
  60. Cyan,
  61. Red,
  62. Magenta,
  63. Brown,
  64. LightGray,
  65. DarkGray,
  66. BrightBlue,
  67. BrightGreen,
  68. BrightCyan,
  69. BrightRed,
  70. BrightMagenta,
  71. Yellow,
  72. White,
  73. };
  74. enum class ANSIColor : byte {
  75. Black = 0,
  76. Red,
  77. Green,
  78. Brown,
  79. Blue,
  80. Magenta,
  81. Cyan,
  82. LightGray,
  83. DarkGray,
  84. BrightRed,
  85. BrightGreen,
  86. Yellow,
  87. BrightBlue,
  88. BrightMagenta,
  89. BrightCyan,
  90. White,
  91. };
  92. static inline VGAColor ansiColorToVGA(ANSIColor color)
  93. {
  94. switch (color) {
  95. case ANSIColor::Black: return VGAColor::Black;
  96. case ANSIColor::Red: return VGAColor::Red;
  97. case ANSIColor::Brown: return VGAColor::Brown;
  98. case ANSIColor::Blue: return VGAColor::Blue;
  99. case ANSIColor::Magenta: return VGAColor::Magenta;
  100. case ANSIColor::Green: return VGAColor::Green;
  101. case ANSIColor::Cyan: return VGAColor::Cyan;
  102. case ANSIColor::LightGray: return VGAColor::LightGray;
  103. case ANSIColor::DarkGray: return VGAColor::DarkGray;
  104. case ANSIColor::BrightRed: return VGAColor::BrightRed;
  105. case ANSIColor::BrightGreen: return VGAColor::BrightGreen;
  106. case ANSIColor::Yellow: return VGAColor::Yellow;
  107. case ANSIColor::BrightBlue: return VGAColor::BrightBlue;
  108. case ANSIColor::BrightMagenta: return VGAColor::BrightMagenta;
  109. case ANSIColor::BrightCyan: return VGAColor::BrightCyan;
  110. case ANSIColor::White: return VGAColor::White;
  111. }
  112. ASSERT_NOT_REACHED();
  113. return VGAColor::LightGray;
  114. }
  115. static inline byte ansiColorToVGA(byte color)
  116. {
  117. return (byte)ansiColorToVGA((ANSIColor)color);
  118. }
  119. void Console::escape$m(const Vector<unsigned>& params)
  120. {
  121. for (auto param : params) {
  122. switch (param) {
  123. case 0:
  124. // Reset
  125. m_currentAttribute = 0x07;
  126. break;
  127. case 1:
  128. // Bold
  129. m_currentAttribute |= 8;
  130. break;
  131. case 30:
  132. case 31:
  133. case 32:
  134. case 33:
  135. case 34:
  136. case 35:
  137. case 36:
  138. case 37:
  139. // Foreground color
  140. m_currentAttribute &= ~0x7;
  141. m_currentAttribute |= ansiColorToVGA(param - 30);
  142. break;
  143. case 40:
  144. case 41:
  145. case 42:
  146. case 43:
  147. case 44:
  148. case 45:
  149. case 46:
  150. case 47:
  151. // Background color
  152. m_currentAttribute &= ~0x70;
  153. m_currentAttribute |= ansiColorToVGA(param - 30) << 8;
  154. break;
  155. }
  156. }
  157. vga_set_attr(m_currentAttribute);
  158. }
  159. void Console::escape$s(const Vector<unsigned>&)
  160. {
  161. m_savedCursorRow = m_cursorRow;
  162. m_savedCursorColumn = m_cursorColumn;
  163. }
  164. void Console::escape$u(const Vector<unsigned>&)
  165. {
  166. m_cursorRow = m_savedCursorRow;
  167. m_cursorColumn = m_savedCursorColumn;
  168. vga_set_cursor(m_cursorRow, m_cursorColumn);
  169. }
  170. void Console::escape$H(const Vector<unsigned>& params)
  171. {
  172. unsigned row = 1;
  173. unsigned col = 1;
  174. if (params.size() >= 1)
  175. row = params[0];
  176. if (params.size() >= 2)
  177. col = params[1];
  178. m_cursorRow = row - 1;
  179. m_cursorColumn = col - 1;
  180. vga_set_cursor(row - 1, col - 1);
  181. }
  182. void Console::escape$J(const Vector<unsigned>& params)
  183. {
  184. int mode = 0;
  185. if (params.size() >= 1)
  186. mode = params[0];
  187. switch (mode) {
  188. case 0:
  189. // FIXME: Clear from cursor to end of screen.
  190. notImplemented();
  191. break;
  192. case 1:
  193. // FIXME: Clear from cursor to beginning of screen.
  194. notImplemented();
  195. break;
  196. case 2:
  197. vga_clear();
  198. break;
  199. case 3:
  200. // FIXME: <esc>[3J should also clear the scrollback buffer.
  201. vga_clear();
  202. break;
  203. }
  204. }
  205. void Console::executeEscapeSequence(byte final)
  206. {
  207. auto paramparts = String((const char*)m_parameters.data(), m_parameters.size()).split(';');
  208. Vector<unsigned> params;
  209. for (auto& parampart : paramparts) {
  210. bool ok;
  211. unsigned value = parseUInt(parampart, ok);
  212. if (!ok) {
  213. // FIXME: Should we do something else?
  214. return;
  215. }
  216. params.append(value);
  217. }
  218. switch (final) {
  219. case 'H': escape$H(params); break;
  220. case 'J': escape$J(params); break;
  221. case 'm': escape$m(params); break;
  222. case 's': escape$s(params); break;
  223. case 'u': escape$u(params); break;
  224. default: break;
  225. }
  226. m_parameters.clear();
  227. m_intermediates.clear();
  228. }
  229. void Console::putChar(char ch)
  230. {
  231. #ifdef CONSOLE_OUT_TO_E9
  232. //if (ch != 27)
  233. IO::out8(0xe9, ch);
  234. #endif
  235. auto scrollup = [&] {
  236. if (m_cursorRow == (m_rows - 1)) {
  237. vga_scroll_up();
  238. } else {
  239. ++m_cursorRow;
  240. }
  241. m_cursorColumn = 0;
  242. };
  243. switch (m_escState) {
  244. case ExpectBracket:
  245. if (ch == '[')
  246. m_escState = ExpectParameter;
  247. else
  248. m_escState = Normal;
  249. return;
  250. case ExpectParameter:
  251. if (isParameter(ch)) {
  252. m_parameters.append(ch);
  253. return;
  254. }
  255. m_escState = ExpectIntermediate;
  256. // fall through
  257. case ExpectIntermediate:
  258. if (isIntermediate(ch)) {
  259. m_intermediates.append(ch);
  260. return;
  261. }
  262. m_escState = ExpectFinal;
  263. // fall through
  264. case ExpectFinal:
  265. if (isFinal(ch)) {
  266. m_escState = Normal;
  267. executeEscapeSequence(ch);
  268. return;
  269. }
  270. m_escState = Normal;
  271. return;
  272. case Normal:
  273. break;
  274. }
  275. switch (ch) {
  276. case '\0':
  277. return;
  278. case '\033':
  279. m_escState = ExpectBracket;
  280. return;
  281. case 8: // Backspace
  282. if (m_cursorColumn) {
  283. --m_cursorColumn;\
  284. vga_set_cursor(m_cursorRow, m_cursorColumn);
  285. vga_putch_at(m_cursorRow, m_cursorColumn, ' ');
  286. return;
  287. }
  288. break;
  289. case '\n':
  290. scrollup();
  291. vga_set_cursor(m_cursorRow, m_cursorColumn);
  292. return;
  293. }
  294. vga_putch_at(m_cursorRow, m_cursorColumn, ch);
  295. ++m_cursorColumn;
  296. if (m_cursorColumn >= m_columns)
  297. scrollup();
  298. vga_set_cursor(m_cursorRow, m_cursorColumn);
  299. }
  300. ssize_t Console::write(const byte* data, size_t size)
  301. {
  302. if (!size)
  303. return 0;
  304. for (size_t i = 0; i < size; ++i)
  305. putChar(data[i]);
  306. return 0;
  307. }