grub2: bring back build of aros-side grub2 tools
[AROS.git] / rom / devs / console / support.c
blobbc583170fffa6a8efcf341ccf0bffeb81a243e6a
1 /*
2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Support functions for console.device
6 Lang: english
7 */
9 #include <proto/exec.h>
10 #include <exec/lists.h>
11 #include <exec/io.h>
12 #include <exec/memory.h>
14 #include <proto/intuition.h>
15 #include <intuition/classes.h>
17 #include <devices/conunit.h>
18 #include <string.h>
19 #include <stdio.h>
21 #include "console_gcc.h"
23 #include "consoleif.h"
25 #define SDEBUG 0
26 #define DEBUG 0
27 #include <aros/debug.h>
29 static BOOL getparamcommand(BYTE *cmd_ptr, UBYTE ** writestr_ptr,
30 UBYTE *numparams_ptr, LONG toparse, IPTR *p_tab, Object *unit,
31 struct ConsoleBase *ConsoleDevice);
32 static BOOL string2command(BYTE *cmd_ptr, UBYTE ** writestr_ptr,
33 UBYTE *numparams_ptr, LONG toparse, IPTR *p_tab, Object *unit,
34 struct ConsoleBase *ConsoleDevice);
36 #define ESC 0x1B
37 #define CSI 0x9B
39 #define NIL 0x00
40 #define BELL 0x07
41 #define BACKSPACE 0x08
42 #define HTAB 0x09
43 #define LINEFEED 0x0A
44 #define VTAB 0x0B
45 #define FORMFEED 0x0C
46 #define CARRIAGE_RETURN 0x0D
47 #define SHIFT_OUT 0x0E
48 #define SHIFT_IN 0x0F
49 #define INDEX 0x84
50 #define NEXT_LINE 0x85
51 #define H_TAB_SET 0x88
52 #define REVERSE_INDEX 0x8D
55 #define FIRST_CSI_CMD 0x40
57 /***********************
58 ** writeToConsole() **
59 ***********************/
62 ** SGR is the command with most params: 4
63 ** stegerg: RKRMs say it can have any number of parameters in any order. So instead of 4
64 ** we assume and hope that there will never be more than 16 params :-\
67 #define MAX_COMMAND_PARAMS 16
70 ULONG writeToConsole(struct ConUnit *unit, STRPTR buf, ULONG towrite,
71 struct ConsoleBase *ConsoleDevice)
73 IPTR param_tab[MAX_COMMAND_PARAMS];
75 BYTE command = 0;
76 UBYTE numparams;
77 UBYTE *orig_write_str, *write_str;
78 LONG written, orig_towrite;
80 write_str = orig_write_str = (UBYTE *) buf;
82 EnterFunc(bug("WriteToConsole(ioreq=%p)\n"));
84 orig_towrite = towrite;
86 D(bug("Number of chars to write %d\n", towrite));
88 /* Interpret string into a command and execute command */
90 /* DEBUG aid */
92 #if DEBUG
94 UWORD i;
95 for (i = 0; i < towrite; i++)
96 kprintf("%x", write_str[i]);
98 kprintf("\n");
101 #endif
102 while (towrite > 0)
104 numparams = 0;
106 if (!string2command(&command, &write_str, &numparams, towrite,
107 param_tab, (Object *) unit, ConsoleDevice))
108 break;
110 Console_UnRenderCursor((Object *) unit);
111 Console_DoCommand((Object *) unit, command, numparams, param_tab);
112 Console_RenderCursor((Object *) unit);
114 towrite = orig_towrite - (write_str - orig_write_str);
115 } /* while (characters left to interpret) */
117 written = write_str - orig_write_str;
119 ReturnInt("WriteToConsole", LONG, written);
123 /**********************
124 ** string2command() **
125 **********************/
128 static const UBYTE str_slm[] = {0x32, 0x30, 0x68}; /* Set linefeed mode */
129 static const UBYTE str_rnm[] = {0x32, 0x30, 0x6C}; /* Reset linefeed mode */
130 static const UBYTE str_ssm[] = {0x3E, 0x31, 0x68}; /* Set autoscroll mode */
131 static const UBYTE str_rsm[] = {0x3E, 0x31, 0x6C}; /* Reset autoscroll mode */
132 static const UBYTE str_swm[] = {0x3E, 0x37, 0x68}; /* Set autowrap mode */
133 static const UBYTE str_rwm[] = {0x3E, 0x37, 0x6C}; /* Reset autowrap mode */
134 static const UBYTE str_dsr[] = {0x36, 0x6E}; /* device status report */
135 static const UBYTE str_con[] = {' ', 'p'}; /* cursor visible */
136 static const UBYTE str_con2[] = {'1', ' ', 'p'}; /* cursor visible */
137 static const UBYTE str_cof[] = {'0', ' ', 'p'}; /* cursor invisible */
138 static const UBYTE str_srq1[] = {' ', 'q'}; /* window status request */
139 static const UBYTE str_srq2[] = {'0', ' ', 'q'}; /* window status request */
141 #define NUM_SPECIAL_COMMANDS 12
142 static const struct special_cmd_descr
144 BYTE Command;
145 STRPTR CommandStr;
146 BYTE Length;
147 } scd_tab[NUM_SPECIAL_COMMANDS] =
149 {C_SET_LF_MODE, (STRPTR) str_slm, 3},
150 {C_RESET_LF_MODE, (STRPTR) str_rnm, 3},
151 {C_SET_AUTOSCROLL_MODE, (STRPTR) str_ssm, 3},
152 {C_RESET_AUTOSCROLL_MODE, (STRPTR) str_rsm, 3},
153 {C_SET_AUTOWRAP_MODE, (STRPTR) str_swm, 3},
154 {C_RESET_AUTOWRAP_MODE, (STRPTR) str_rwm, 3},
155 {C_DEVICE_STATUS_REPORT, (STRPTR) str_dsr, 2},
156 {C_CURSOR_VISIBLE, (STRPTR) str_con, 2},
157 {C_CURSOR_VISIBLE, (STRPTR) str_con2, 3},
158 {C_CURSOR_INVISIBLE, (STRPTR) str_cof, 3},
159 {C_WINDOW_STATUS_REQUEST, (STRPTR) str_srq1, 2},
160 {C_WINDOW_STATUS_REQUEST, (STRPTR) str_srq2, 3}
163 #if DEBUG
164 static UBYTE *cmd_names[NUM_CONSOLE_COMMANDS] = {
166 "Ascii", /* C_ASCII = 0 */
168 "Esc", /* C_ESC */
169 "Bell", /* C_BELL, */
170 "Backspace", /* C_BACKSPACE, */
171 "HTab", /* C_HTAB, */
172 "Linefeed", /* C_LINEFEED, */
173 "VTab", /* C_VTAB, */
174 "Formefeed", /* C_FORMFEED, */
175 "Carriage return", /* C_CARRIAGE_RETURN, */
176 "Shift In", /* C_SHIFT_IN, */
177 "Shift Out", /* C_SHIFT_OUT, */
178 "Index", /* C_INDEX, */
179 "Nex Line", /* C_NEXT_LINE, */
180 "Tab set", /* C_H_TAB_SET, */
181 "Reverse Idx", /* C_REVERSE_IDX, */
182 "Set LF Mode", /* C_SET_LF_MODE, */
183 "Reset LF Mode", /* C_RESET_lF_MODE, */
184 "Device Status Report", /* C_DEVICE_STATUS_REPORT, */
186 "Insert Char", /* C_INSERT_CHAR, */
187 "Cursor Up", /* C_CURSOR_UP, */
188 "Cursor Down", /* C_CURSOR_DOWN, */
189 "Cursor Forward", /* C_CURSOR_FORWARD, */
190 "Cursor Backward", /* C_CURSOR_BACKWARD, */
191 "Cursor Next Line", /* C_CURSOR_NEXT_LINE, */
192 "Cursor Prev Line", /* C_CURSOR_PREV_LINE, */
193 "Cursor Pos", /* C_CURSOR_POS, */
194 "Cursor HTab", /* C_CURSOR_HTAB, */
195 "Erase In Display", /* C_ERASE_IN_DISPLAY, */
196 "Erase In Line", /* C_ERASE_IN_LINE, */
197 "Insert Line", /* C_INSERT_LINE, */
198 "Delete Line", /* C_DELETE_LINE, */
199 "Delete Char", /* C_DELETE_CHAR, */
200 "Scroll Up", /* C_SCROLL_UP, */
201 "Scroll Down", /* C_SCROLL_DOWN, */
202 "Cursor Tab Ctrl", /* C_CURSOR_TAB_CTRL, */
203 "Cursor Backtab", /* C_CURSOR_BACKTAB, */
204 "Select Graphic Rendition", /* C_SELECT_GRAPHIC_RENDITION */
205 "Window Status Request", /* C_WINDOW_STATUS_REQUEST */
206 "Cursor Visible", /* C_CURSOR_VISIBLE, */
207 "Cursor Invisible", /* C_CURSOR_INVISIBLE, */
208 "Set Raw Events", /* C_SET_RAWEVENTS, */
209 "Reset Raw Events", /* C_RESET_RAWEVENTS */
210 "Set Auto Wrap Mode", /* C_SET_AUTOWRAP_MODE */
211 "Reset Auto Wrap Mode", /* C_RESET_AUTOWRAP_MODE */
212 "Set Auto Scroll Mode", /* C_SET_AUTOSCROLL_MODE */
213 "Reset Auto Scroll Mode", /* C_RESET_AUTOSCROLL_MODE */
214 "Set Page Length", /* C_SET_PAGE_LENGTH */
215 "Set Line Length", /* C_SET_LINE_LENGTH */
216 "Set Left Offset", /* C_SET_LEFT_OFFSET */
217 "Set Top Offset" /* C_SET_TOP_OFFSET */
219 #endif
221 static BOOL check_special(STRPTR string, LONG toparse)
223 return ((*string == CSI) ||
224 (toparse >= 2 && (string[0] == ESC) && (string[1] == '[')) || /* CSI */
225 (*string == NIL) ||
226 (*string == BELL) ||
227 (*string == BACKSPACE) ||
228 (*string == HTAB) ||
229 (*string == LINEFEED) ||
230 (*string == FORMFEED) ||
231 (*string == CARRIAGE_RETURN) ||
232 (*string == SHIFT_OUT) ||
233 (*string == SHIFT_IN) ||
234 (*string == ESC) ||
235 (*string == INDEX) ||
236 (*string == H_TAB_SET) || (*string == REVERSE_INDEX));
239 static BOOL string2command(BYTE *cmd_ptr, UBYTE ** writestr_ptr,
240 UBYTE *numparams_ptr, LONG toparse, IPTR *p_tab, Object *unit,
241 struct ConsoleBase *ConsoleDevice)
243 UBYTE *write_str = *writestr_ptr;
244 UBYTE *csi_str = write_str;
245 LONG csi_toparse = 0;
247 BOOL found = FALSE, csi = FALSE;
249 EnterFunc(bug("StringToCommand(toparse=%d)\n", toparse));
251 /* Look for <CSI> */
252 if (*write_str == CSI)
254 csi_str++;
255 csi = TRUE;
256 csi_toparse = toparse - 1;
258 else if (toparse >= 2)
260 if ((write_str[0] == ESC) && (write_str[1] == '['))
262 csi_str += 2;
263 csi_toparse = toparse - 2;
264 csi = TRUE;
268 if (csi)
270 D(bug("CSI found, getting command\n"));
272 /* Search for the longest commands first */
274 if (!found)
276 BYTE i;
277 /* Look for some special commands */
278 for (i = 0; ((i < NUM_SPECIAL_COMMANDS) && (!found)); i++)
280 /* Check whether command sequence is longer than input */
281 if (scd_tab[i].Length > csi_toparse)
282 continue; /* if so, check next command sequence */
284 D(bug
285 ("Comparing for special command %d, idx %d, cmdstr %p, len %d, csistr %p \n",
286 scd_tab[i].Command, i, scd_tab[i].CommandStr,
287 scd_tab[i].Length, csi_str));
288 /* Command match ? */
289 if (0 == strncmp(csi_str, scd_tab[i].CommandStr,
290 scd_tab[i].Length))
292 D(bug("Special command found\n"));
293 csi_str += scd_tab[i].Length;
294 *cmd_ptr = scd_tab[i].Command;
296 found = TRUE;
298 } /* for (each special command) */
301 /* A parameter command? (I.e. one of the commands that take
302 * parameters) */
303 if (!found)
304 found =
305 getparamcommand(cmd_ptr, &csi_str, numparams_ptr,
306 csi_toparse, p_tab, unit, ConsoleDevice);
308 } /* if (CSI was found) */
310 if (found)
311 write_str = csi_str;
312 else
314 /* Look for standalone codes */
315 switch (*write_str)
317 case NIL:
318 *cmd_ptr = C_NIL;
319 found = TRUE;
320 break;
322 case BELL:
323 *cmd_ptr = C_BELL;
324 found = TRUE;
325 break;
327 case BACKSPACE:
328 *cmd_ptr = C_BACKSPACE;
329 found = TRUE;
330 break;
332 case HTAB:
333 *cmd_ptr = C_HTAB;
334 found = TRUE;
335 break;
337 case LINEFEED:
338 *cmd_ptr = C_LINEFEED;
339 found = TRUE;
340 break;
342 case VTAB:
343 *cmd_ptr = C_VTAB;
344 found = TRUE;
345 break;
347 case FORMFEED:
348 *cmd_ptr = C_FORMFEED;
349 found = TRUE;
350 break;
352 case CARRIAGE_RETURN:
353 *cmd_ptr = C_CARRIAGE_RETURN;
354 found = TRUE;
355 break;
357 case SHIFT_OUT:
358 *cmd_ptr = C_SHIFT_OUT;
359 found = TRUE;
360 break;
362 case SHIFT_IN:
363 *cmd_ptr = C_SHIFT_IN;
364 found = TRUE;
365 break;
367 case ESC:
368 *cmd_ptr = C_ESC;
369 found = TRUE;
370 break;
372 case INDEX:
373 *cmd_ptr = C_INDEX;
374 found = TRUE;
375 break;
377 case NEXT_LINE:
378 *cmd_ptr = C_NEXT_LINE;
379 found = TRUE;
380 break;
382 case H_TAB_SET:
383 *cmd_ptr = C_H_TAB_SET;
384 found = TRUE;
385 break;
387 case REVERSE_INDEX:
388 *cmd_ptr = C_REVERSE_IDX;
389 found = TRUE;
390 break;
391 } /* (switch) */
393 if (found)
395 /* Found special char. Increase pointer */
397 write_str++;
401 if (!found) /* Still not any found? Try to print as plain ASCII */
403 *cmd_ptr = C_ASCII_STRING;
405 p_tab[0] = (IPTR) write_str;
406 *numparams_ptr = 2;
407 found = TRUE;
411 toparse--;
412 write_str++;
414 while (toparse && !check_special(write_str, toparse));
416 /* store the string length */
417 p_tab[1] = (IPTR) (write_str - (UBYTE *) p_tab[0]);
420 D(bug("FOUND CMD: %s\n", cmd_names[*cmd_ptr]));
422 /* Return pointer to first character AFTER last interpreted char */
423 *writestr_ptr = write_str;
425 ReturnBool("StringToCommand", found);
429 /************************
430 ** getparamcommand() **
431 ************************/
433 /* !!! IMPORTANT !!!
434 If you add a command here, you should also add default values for
435 its parameters in Console::GetDefaultParams()
437 static const struct Command
439 BYTE Command;
440 UBYTE MaxParams;
442 } csi2command[] =
444 {C_INSERT_CHAR, 1}, /* 0x40 @ */
445 {C_CURSOR_UP, 1}, /* 0x41 A */
446 {C_CURSOR_DOWN, 1}, /* 0x42 B */
447 {C_CURSOR_FORWARD, 1}, /* 0x43 C */
448 {C_CURSOR_BACKWARD, 1}, /* 0x44 D */
449 {C_CURSOR_NEXT_LINE, 1}, /* 0x45 E */
450 {C_CURSOR_PREV_LINE, 1}, /* 0x46 F */
451 {-1, }, /* 0x47 G */
452 {C_CURSOR_POS, 2}, /* 0x48 H */
453 {C_CURSOR_HTAB, 1}, /* 0x49 I */
454 {C_ERASE_IN_DISPLAY, 0}, /* 0x4A J */
455 {C_ERASE_IN_LINE, 0}, /* 0x4B K */
456 {C_INSERT_LINE, 0}, /* 0x4C L */
457 {C_DELETE_LINE, 0}, /* 0x4D M */
458 {-1, }, /* 0x4E N */
459 {-1, }, /* 0x4F O */
460 {C_DELETE_CHAR, 1}, /* 0x50 P */
461 {-1, }, /* 0x51 Q */
462 {-1, }, /* 0x52 R */
463 {C_SCROLL_UP, 1}, /* 0x53 S */
464 {C_SCROLL_DOWN, 1}, /* 0x54 T */
465 {-1, }, /* 0x55 U */
466 {-1, }, /* 0x56 V */
467 {C_CURSOR_TAB_CTRL, 1}, /* 0x57 W */
468 {-1, }, /* 0x58 X */
469 {-1, }, /* 0x59 Y */
470 {C_CURSOR_BACKTAB, 1}, /* 0x5A Z */
471 {-1, }, /* 0x5B [ */
472 {-1, }, /* 0x5C \ */
473 {-1, }, /* 0x5D ] */
474 {-1, }, /* 0x5E ^ */
475 {-1, }, /* 0x5F _ */
476 {-1, }, /* 0x60 ` */
477 {-1, }, /* 0x61 a */
478 {-1, }, /* 0x62 b */
479 {-1, }, /* 0x63 c */
480 {-1, }, /* 0x64 d */
481 {-1, }, /* 0x65 e */
482 {-1, }, /* 0x66 f */
483 {-1, }, /* 0x67 g */
484 {-1, }, /* 0x68 h */
485 {-1, }, /* 0x69 i */
486 {-1, }, /* 0x6A j */
487 {-1, }, /* 0x6B k */
488 {-1, }, /* 0x6C l */
489 {C_SELECT_GRAPHIC_RENDITION, MAX_COMMAND_PARAMS}, /* 0x6D m */
490 {-1, }, /* 0x6E n */
491 {-1, }, /* 0x6F o */
492 {-1, }, /* 0x70 p */
493 {-1, }, /* 0x71 q */
494 {-1, }, /* 0x72 r */
495 {-1, }, /* 0x73 s */
496 {C_SET_PAGE_LENGTH, 1}, /* 0x74 t */
497 {C_SET_LINE_LENGTH, }, /* 0x75 u */
498 {-1, }, /* 0x76 v */
499 {-1, }, /* 0x77 w */
500 {C_SET_LEFT_OFFSET, 1}, /* 0x78 x */
501 {C_SET_TOP_OFFSET, 1}, /* 0x79 y */
502 {-1, }, /* 0x7A z */
503 {C_SET_RAWEVENTS, MAX_COMMAND_PARAMS}, /* 0x7B { */
504 {-1, }, /* 0x7C | */
505 {C_RESET_RAWEVENTS, MAX_COMMAND_PARAMS}, /* 0x7D } */
509 #define PARAM_BUF_SIZE MAX_COMMAND_PARAMS
510 /* Parameters for commands are parsed and filled into this one */
511 struct cmd_params
513 UBYTE numparams; /* Parameters stored */
515 /* Since parameters may be optional, only supplied parameters
516 are saved, along with their number. For example
517 for the command CURSOR POSITION, if only the second parameter
518 (column) is specified in the write stream, then
519 numparams will be 1 and for the one entry, paramno will be 1
520 (C counting) and val will be <column>.
521 Row will have to be set to some default value.
523 struct cmd_param
525 UBYTE paramno; /* Starts counting at 0 */
526 UBYTE val;
527 } tab[PARAM_BUF_SIZE];
531 static BOOL getparamcommand(BYTE *cmd_ptr, UBYTE ** writestr_ptr,
532 UBYTE *numparams_ptr, LONG toparse, IPTR *p_tab, Object *unit,
533 struct ConsoleBase *ConsoleDevice)
535 /* This function checks for a command with parameters in
536 ** the string. The problem is that the parameters come
537 ** before the comand ID, and the parameters are optional.
538 ** This means that a parameter which has the same value
539 ** as a command ID may be mistakenly taken for being
540 ** end of the command. Therefore we must continue scanning
541 ** even if we found a command ID.
544 struct cmd_params params = { };
545 BYTE cmd = -1;
546 BYTE cmd_next_idx = 0; /* Index to byte after the command */
548 /* write_str points to first character after <CSI> */
549 UBYTE *write_str = *writestr_ptr;
551 UBYTE num_params = 0;
552 BOOL done = FALSE, found = FALSE;
553 BOOL next_can_be_separator = TRUE,
554 next_can_be_param = TRUE,
555 next_can_be_commandid = TRUE, last_was_param = FALSE;
556 UBYTE num_separators_found = 0;
558 while (!done)
560 /* In case it's a parameter */
562 if (toparse <= 0)
564 done = TRUE;
565 break;
568 switch (*write_str)
570 case 0x40:
571 case 0x41:
572 case 0x42:
573 case 0x43:
574 case 0x44:
575 case 0x45:
576 case 0x46:
577 case 0x48:
578 case 0x49:
580 case 0x4A:
581 case 0x4B:
582 case 0x4C:
583 case 0x4D:
585 case 0x50:
586 case 0x53:
587 case 0x54:
588 case 0x57:
589 case 0x5A:
590 case 0x6D:
591 case 0x74:
592 case 0x75:
593 case 0x78:
594 case 0x79:
595 case 0x7B:
596 case 0x7D:
598 UBYTE idx = *write_str - FIRST_CSI_CMD;
599 UBYTE maxparams = csi2command[idx].MaxParams;
601 if (next_can_be_commandid)
603 /* FIXME: Should also do a MinParams compare */
604 if (num_params <= maxparams) /* Valid command? */
607 /* Assure that there are not too many separators in
608 * a command */
609 if ((num_separators_found < maxparams)
610 /* FIXME: 0-param commands can be moved to special-command-handlin in string2command() */
611 || ((num_separators_found == 0)
612 && (maxparams == 0)))
614 cmd = csi2command[idx].Command;
616 /* Save index to where the next command will
617 * start */
618 cmd_next_idx = write_str - *writestr_ptr + 1;
620 params.numparams = num_params;
625 done = TRUE;
627 break;
630 case ';': /* parameter separator, skip it */
632 if (!next_can_be_separator)
634 /* Error */
635 done = TRUE;
636 break;
639 next_can_be_separator = FALSE;
640 next_can_be_param = TRUE;
641 next_can_be_commandid = FALSE;
642 last_was_param = FALSE;
644 num_separators_found++;
646 break;
648 case '0':
649 case '1':
650 case '2':
651 case '3':
652 case '4':
653 case '5':
654 case '6':
655 case '7':
656 case '8':
657 case '9':
658 case '>': /* because of SGR background color param :-( */
659 if (!next_can_be_param)
661 /* Error */
662 done = TRUE;
663 break;
666 if (!last_was_param)
668 num_params++;
669 if (num_params > MAX_COMMAND_PARAMS)
671 done = TRUE;
672 break;
674 params.tab[num_params - 1].paramno = num_params - 1;
675 params.tab[num_params - 1].val = 0;
677 last_was_param = TRUE;
680 params.tab[num_params - 1].val *= 10;
681 if (*write_str == '>')
683 params.tab[num_params - 1].val += 5;
685 else
687 params.tab[num_params - 1].val += (*write_str) - '0';
690 next_can_be_separator = TRUE;
691 next_can_be_commandid = TRUE;
692 break;
694 default:
695 /* Error */
696 done = TRUE;
697 break;
698 } /* switch */
700 write_str++;
701 toparse--;
702 } /* while (!done) */
704 if (cmd != -1)
706 *cmd_ptr = cmd;
707 found = TRUE;
709 /* Continue parsing on the first byte after the command */
710 *writestr_ptr += cmd_next_idx;
713 if (found)
715 UBYTE i;
716 /* First fill in some default values in p_tab */
717 Console_GetDefaultParams(unit, *cmd_ptr, p_tab);
719 for (i = 0; i < params.numparams; i++)
721 /* Override with parsed values */
722 D(bug("CMD %s: Setting param %d to %d\n", cmd_names[*cmd_ptr],
723 params.tab[i].paramno, params.tab[i].val));
725 p_tab[params.tab[i].paramno] = params.tab[i].val;
728 *numparams_ptr = params.numparams;
731 return found;
734 VOID printstring(STRPTR string, ULONG len,
735 struct ConsoleBase *ConsoleDevice)
737 while (len--)
739 kprintf("%d/%c ", *string, *string);
740 string++;
743 kprintf("\n");