2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
5 Desc: Support functions for console.device
9 #include <proto/exec.h>
10 #include <exec/lists.h>
12 #include <exec/memory.h>
14 #include <proto/intuition.h>
15 #include <intuition/classes.h>
17 #include <devices/conunit.h>
21 #include "console_gcc.h"
23 #include "consoleif.h"
27 #include <aros/debug.h>
29 static BOOL
getparamcommand(BYTE
*cmd_ptr
, UBYTE
**writestr_ptr
, UBYTE
*numparams_ptr
, LONG toparse
, IPTR
*p_tab
, Object
*unit
, struct ConsoleBase
*ConsoleDevice
);
30 static BOOL
string2command(BYTE
*cmd_ptr
, UBYTE
**writestr_ptr
, UBYTE
*numparams_ptr
, LONG toparse
, IPTR
*p_tab
, Object
*unit
, struct ConsoleBase
*ConsoleDevice
);
37 #define BACKSPACE 0x08
42 #define CARRIAGE_RETURN 0x0D
43 #define SHIFT_OUT 0x0E
46 #define NEXT_LINE 0x85
47 #define H_TAB_SET 0x88
48 #define REVERSE_INDEX 0x8D
51 #define FIRST_CSI_CMD 0x40
53 /***********************
54 ** writeToConsole() **
55 ***********************/
58 ** SGR is the command with most params: 4
59 ** stegerg: RKRMs say it can have any number of parameters in any order. So instead of 4
60 ** we assume and hope that there will never be more than 16 params :-\
63 #define MAX_COMMAND_PARAMS 16
66 ULONG
writeToConsole(struct ConUnit
*unit
, STRPTR buf
, ULONG towrite
, struct ConsoleBase
*ConsoleDevice
)
68 IPTR param_tab
[MAX_COMMAND_PARAMS
];
72 UBYTE
*orig_write_str
, *write_str
;
73 LONG written
, orig_towrite
;
75 write_str
= orig_write_str
= (UBYTE
*)buf
;
78 EnterFunc(bug("WriteToConsole(ioreq=%p)\n"));
81 orig_towrite
= towrite
;
83 D(bug("Number of chars to write %d\n", towrite
));
86 /* Interpret string into a command and execute command */
93 for (i
= 0; i
< towrite
; i
++)
94 kprintf("%x", write_str
[i
]);
104 if (!string2command(&command
, &write_str
, &numparams
, towrite
, param_tab
, (Object
*)unit
, ConsoleDevice
))
108 Console_UnRenderCursor((Object
*)unit
);
109 Console_DoCommand((Object
*)unit
, command
, numparams
, param_tab
);
110 Console_RenderCursor((Object
*)unit
);
112 towrite
= orig_towrite
- (write_str
- orig_write_str
);
114 } /* while (characters left to interpret) */
116 written
= write_str
- orig_write_str
;
118 ReturnInt("WriteToConsole", LONG
, written
);
122 /**********************
123 ** string2command() **
124 **********************/
127 static const UBYTE str_slm
[] = {0x32, 0x30, 0x68 }; /* Set linefeed mode */
128 static const UBYTE str_rnm
[] = {0x32, 0x30, 0x6C }; /* Reset linefeed mode */
129 static const UBYTE str_ssm
[] = {0x3E, 0x31, 0x68 }; /* Set autoscroll mode */
130 static const UBYTE str_rsm
[] = {0x3E, 0x31, 0x6C }; /* Reset autoscroll mode */
131 static const UBYTE str_swm
[] = {0x3E, 0x37, 0x68 }; /* Set autowrap mode */
132 static const UBYTE str_rwm
[] = {0x3E, 0x37, 0x6C }; /* Reset autowrap mode */
133 static const UBYTE str_dsr
[] = {0x36, 0x6E }; /* device status report */
134 static const UBYTE str_con
[] = {' ', 'p'}; /* cursor visible */
135 static const UBYTE str_con2
[] = {'1', ' ', 'p'}; /* cursor visible */
136 static const UBYTE str_cof
[] = {'0', ' ', 'p'}; /* cursor invisible */
137 static const UBYTE str_srq1
[] = {' ', 'q'}; /* window status request */
138 static const UBYTE str_srq2
[] = {'0', ' ','q'}; /* window status request */
140 #define NUM_SPECIAL_COMMANDS 12
141 static const struct special_cmd_descr
146 } scd_tab
[NUM_SPECIAL_COMMANDS
] = {
148 {C_SET_LF_MODE
, (STRPTR
)str_slm
, 3 },
149 {C_RESET_LF_MODE
, (STRPTR
)str_rnm
, 3 },
150 {C_SET_AUTOSCROLL_MODE
, (STRPTR
)str_ssm
, 3 },
151 {C_RESET_AUTOSCROLL_MODE
, (STRPTR
)str_rsm
, 3 },
152 {C_SET_AUTOWRAP_MODE
, (STRPTR
)str_swm
, 3 },
153 {C_RESET_AUTOWRAP_MODE
, (STRPTR
)str_rwm
, 3 },
154 {C_DEVICE_STATUS_REPORT
, (STRPTR
)str_dsr
, 2 },
155 {C_CURSOR_VISIBLE
, (STRPTR
)str_con
, 2 },
156 {C_CURSOR_VISIBLE
, (STRPTR
)str_con2
, 3 },
157 {C_CURSOR_INVISIBLE
, (STRPTR
)str_cof
, 3 },
158 {C_WINDOW_STATUS_REQUEST
, (STRPTR
)str_srq1
, 2 },
159 {C_WINDOW_STATUS_REQUEST
, (STRPTR
)str_srq2
, 3 }
163 static UBYTE
*cmd_names
[NUM_CONSOLE_COMMANDS
] =
166 "Ascii", /* C_ASCII = 0 */
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 */
221 static BOOL
check_special(STRPTR string
, LONG toparse
)
225 (*string
== CSI
) || (toparse
>= 2 && (string
[0] == ESC
) && (string
[1] == '[')) || /* CSI */
228 (*string
== BACKSPACE
) ||
230 (*string
== LINEFEED
) ||
231 (*string
== FORMFEED
) ||
232 (*string
== CARRIAGE_RETURN
) ||
233 (*string
== SHIFT_OUT
) ||
234 (*string
== SHIFT_IN
) ||
236 (*string
== INDEX
) ||
237 (*string
== H_TAB_SET
) ||
238 (*string
== REVERSE_INDEX
)
242 static BOOL
string2command( BYTE
*cmd_ptr
243 , UBYTE
**writestr_ptr
244 , UBYTE
*numparams_ptr
248 , struct ConsoleBase
*ConsoleDevice
)
250 UBYTE
*write_str
= *writestr_ptr
;
252 UBYTE
*csi_str
= write_str
;
253 LONG csi_toparse
= 0;
259 EnterFunc(bug("StringToCommand(toparse=%d)\n", toparse
));
263 if (*write_str
== CSI
)
268 csi_toparse
= toparse
- 1;
270 else if (toparse
>= 2)
272 if ( (write_str
[0] == ESC
) && (write_str
[1] == '[') )
275 csi_toparse
= toparse
- 2;
282 D(bug("CSI found, getting command\n"));
284 /* Search for the longest commands first */
289 /* Look for some special commands */
290 for (i
= 0; ((i
< NUM_SPECIAL_COMMANDS
) && (!found
)) ; i
++ )
292 /* Check whether command sequence is longer than input */
293 if (scd_tab
[i
].Length
> csi_toparse
)
294 continue; /* if so, check next command sequence */
296 D(bug("Comparing for special command %d, idx %d, cmdstr %p, len %d, csistr %p \n",
297 scd_tab
[i
].Command
, i
, scd_tab
[i
].CommandStr
, scd_tab
[i
].Length
, csi_str
));
298 /* Command match ? */
299 if (0 == strncmp(csi_str
, scd_tab
[i
].CommandStr
, scd_tab
[i
].Length
))
301 D(bug("Special command found\n"));
302 csi_str
+= scd_tab
[i
].Length
;
303 *cmd_ptr
= scd_tab
[i
].Command
;
308 } /* for (each special command) */
312 /* A parameter command ? (Ie. one of the commands that takes parameters) */
314 found
= getparamcommand(cmd_ptr
, &csi_str
, numparams_ptr
, csi_toparse
, p_tab
, unit
, ConsoleDevice
);
316 } /* if (CSI was found) */
322 /* Look for standalone codes */
336 *cmd_ptr
= C_BACKSPACE
;
346 *cmd_ptr
= C_LINEFEED
;
356 *cmd_ptr
= C_FORMFEED
;
360 case CARRIAGE_RETURN
:
361 *cmd_ptr
= C_CARRIAGE_RETURN
;
366 *cmd_ptr
= C_SHIFT_OUT
;
371 *cmd_ptr
= C_SHIFT_IN
;
386 *cmd_ptr
= C_NEXT_LINE
;
391 *cmd_ptr
= C_H_TAB_SET
;
396 *cmd_ptr
= C_REVERSE_IDX
;
404 /* Found special char. Increase pointer */
411 if (!found
) /* Still not any found ? Try to print as plain ASCII */
413 *cmd_ptr
= C_ASCII_STRING
;
415 p_tab
[0] = (IPTR
)write_str
;
423 } while (toparse
&& !check_special(write_str
, toparse
));
425 p_tab
[1] = (IPTR
)(write_str
- (UBYTE
*)p_tab
[0]); /* store the string length */
428 D(bug("FOUND CMD: %s\n", cmd_names
[*cmd_ptr
]));
430 /* Return pointer to first character AFTER last interpreted char */
431 *writestr_ptr
= write_str
;
433 ReturnBool ("StringToCommand", found
);
437 /************************
438 ** getparamcommand() **
439 ************************/
442 If you add a command here, you should also add default values for
443 its parameters in Console::GetDefaultParams()
445 static const struct Command
452 { C_INSERT_CHAR
, 1 }, /* 0x40 @ */
453 { C_CURSOR_UP
, 1 }, /* 0x41 A */
454 { C_CURSOR_DOWN
, 1 }, /* 0x42 B */
455 { C_CURSOR_FORWARD
, 1 }, /* 0x43 C */
456 { C_CURSOR_BACKWARD
, 1 }, /* 0x44 D */
457 { C_CURSOR_NEXT_LINE
, 1 }, /* 0x45 E */
458 { C_CURSOR_PREV_LINE
, 1 }, /* 0x46 F */
459 { -1 , }, /* 0x47 G */
460 { C_CURSOR_POS
, 2 }, /* 0x48 H */
461 { C_CURSOR_HTAB
, 1 }, /* 0x49 I */
463 { C_ERASE_IN_DISPLAY
, 0 }, /* 0x4A J */
464 { C_ERASE_IN_LINE
, 0 }, /* 0x4B K */
465 { C_INSERT_LINE
, 0 }, /* 0x4C L */
466 { C_DELETE_LINE
, 0 }, /* 0x4D M */
467 { -1 , }, /* 0x4E N */
468 { -1 , }, /* 0x4F O */
469 { C_DELETE_CHAR
, 1 }, /* 0x50 P */
470 { -1 , }, /* 0x51 Q */
471 { -1 , }, /* 0x52 R */
472 { C_SCROLL_UP
, 1 }, /* 0x53 S */
473 { C_SCROLL_DOWN
, 1 }, /* 0x54 T */
474 { -1 , }, /* 0x55 U */
475 { -1 , }, /* 0x56 V */
476 { C_CURSOR_TAB_CTRL
, 1 }, /* 0x57 W */
477 { -1 , }, /* 0x58 X */
478 { -1 , }, /* 0x59 Y */
479 { C_CURSOR_BACKTAB
, 1 }, /* 0x5A Z */
480 { -1 , }, /* 0x5B [ */
481 { -1 , }, /* 0x5C \ */
482 { -1 , }, /* 0x5D ] */
483 { -1 , }, /* 0x5E ^ */
484 { -1 , }, /* 0x5F _ */
485 { -1 , }, /* 0x60 ` */
486 { -1 , }, /* 0x61 a */
487 { -1 , }, /* 0x62 b */
488 { -1 , }, /* 0x63 c */
489 { -1 , }, /* 0x64 d */
490 { -1 , }, /* 0x65 e */
491 { -1 , }, /* 0x66 f */
492 { -1 , }, /* 0x67 g */
493 { -1 , }, /* 0x68 h */
494 { -1 , }, /* 0x69 i */
495 { -1 , }, /* 0x6A j */
496 { -1 , }, /* 0x6B k */
497 { -1 , }, /* 0x6C l */
498 { C_SELECT_GRAPHIC_RENDITION
, MAX_COMMAND_PARAMS
}, /* 0x6D m */
499 { -1 , }, /* 0x6E n */
500 { -1 , }, /* 0x6F o */
501 { -1 , }, /* 0x70 p */
502 { -1 , }, /* 0x71 q */
503 { -1 , }, /* 0x72 r */
504 { -1 , }, /* 0x73 s */
505 { C_SET_PAGE_LENGTH
, 1 }, /* 0x74 t */
506 { C_SET_LINE_LENGTH
, }, /* 0x75 u */
507 { -1 , }, /* 0x76 v */
508 { -1 , }, /* 0x77 w */
509 { C_SET_LEFT_OFFSET
, 1 }, /* 0x78 x */
510 { C_SET_TOP_OFFSET
, 1 }, /* 0x79 y */
511 { -1 , }, /* 0x7A z */
512 { C_SET_RAWEVENTS
, MAX_COMMAND_PARAMS
}, /* 0x7B { */
513 { -1 , }, /* 0x7C | */
514 { C_RESET_RAWEVENTS
, MAX_COMMAND_PARAMS
}, /* 0x7D } */
518 #define PARAM_BUF_SIZE MAX_COMMAND_PARAMS
519 /* Parameters for commands are parsed and filled into this one */
522 UBYTE numparams
; /* Parameters stored */
524 /* Since parameters may be optional, only supplied parameters
525 are saved, along with their number. For example
526 for the command CURSOR POSITION, if only the sencond parameter
527 (column) is specified in the write stream, then
528 numparams will be 1 and for the one entry, paramno will be 1 (C counting)
529 and val will be <column>.
530 Row will have to be set to some default value.
534 UBYTE paramno
; /* Starts counting at 0 */
536 } tab
[PARAM_BUF_SIZE
];
540 static BOOL
getparamcommand(BYTE
*cmd_ptr
541 , UBYTE
**writestr_ptr
542 , UBYTE
*numparams_ptr
546 , struct ConsoleBase
*ConsoleDevice
)
548 /* This function checks for a command with parameters in
549 ** the string. The problem is that the parameters come
550 ** before the comand ID, and the parameters are optional.
551 ** This means that a parameter which has the same value
552 ** as a command ID may be mistakenly taken for being
553 ** end of the command. Therefore we must continue scanning
554 ** even if we found a command ID.
557 struct cmd_params params
= {};
560 BYTE cmd_next_idx
= 0; /* Index to byte after the command */
562 /* write_str points to first character after <CSI> */
563 UBYTE
*write_str
= *writestr_ptr
;
565 UBYTE num_params
= 0;
570 BOOL next_can_be_separator
= TRUE
,
571 next_can_be_param
= TRUE
,
572 next_can_be_commandid
= TRUE
,
573 last_was_param
= FALSE
;
575 UBYTE num_separators_found
= 0;
579 /* In case it's a parameter */
617 UBYTE idx
= *write_str
- FIRST_CSI_CMD
;
618 UBYTE maxparams
= csi2command
[idx
].MaxParams
;
620 if (next_can_be_commandid
)
622 /* FIXME: Should also do a MinParams compare */
623 if (num_params
<= maxparams
) /* Valid command ? */
626 /* Assure that there are not to many separators in a command */
627 if ((num_separators_found
< maxparams
)
628 /* FIXME: 0-param commands can be moved to special-command-handlin in string2command() */
629 || ((num_separators_found
== 0) && (maxparams
== 0)))
631 cmd
= csi2command
[idx
].Command
;
633 /* Save index to where the next command will start */
634 cmd_next_idx
= write_str
- *writestr_ptr
+ 1;
636 params
.numparams
= num_params
;
646 case ';': /* parameter separator, skip it */
648 if (!next_can_be_separator
)
655 next_can_be_separator
= FALSE
;
656 next_can_be_param
= TRUE
;
657 next_can_be_commandid
= FALSE
;
658 last_was_param
= FALSE
;
660 num_separators_found
++;
674 case '>': /* because of SGR background color param :-( */
675 if (!next_can_be_param
)
685 if (num_params
> MAX_COMMAND_PARAMS
)
690 params
.tab
[num_params
- 1].paramno
= num_params
- 1;
691 params
.tab
[num_params
- 1].val
= 0;
693 last_was_param
= TRUE
;
696 params
.tab
[num_params
- 1].val
*= 10;
697 if (*write_str
== '>')
699 params
.tab
[num_params
- 1].val
+= 5;
701 params
.tab
[num_params
- 1].val
+= (*write_str
) - '0';
704 next_can_be_separator
= TRUE
;
705 next_can_be_commandid
= TRUE
;
719 } /* while (!done) */
726 /* Continue parsing on the first byte after the command */
727 *writestr_ptr
+= cmd_next_idx
;
733 /* First fill in some default values in p_tab */
734 Console_GetDefaultParams(unit
, *cmd_ptr
, p_tab
);
736 for (i
= 0; i
< params
.numparams
; i
++)
738 /* Override with parsed values */
739 D(bug("CMD %s: Setting param %d to %d\n"
740 , cmd_names
[*cmd_ptr
]
741 , params
.tab
[i
].paramno
742 , params
.tab
[i
].val
));
744 p_tab
[params
.tab
[i
].paramno
] = params
.tab
[i
].val
;
747 *numparams_ptr
= params
.numparams
;
753 VOID
printstring(STRPTR string
, ULONG len
, struct ConsoleBase
*ConsoleDevice
)
757 kprintf("%d/%c ", *string
, *string
);