some fixes to accented characters
[tangerine.git] / rom / devs / console / support.c
blob77ac2f2e8254c4d298cd65ba9ba85fa88c39bff9
1 /*
2 Copyright © 1995-2001, 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, 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);
32 #define ESC 0x1B
33 #define CSI 0x9B
35 #define BELL 0x07
36 #define BACKSPACE 0x08
37 #define HTAB 0x09
38 #define LINEFEED 0x0A
39 #define VTAB 0x0B
40 #define FORMFEED 0x0C
41 #define CARRIAGE_RETURN 0x0D
42 #define SHIFT_OUT 0x0E
43 #define SHIFT_IN 0x0F
44 #define INDEX 0x84
45 #define NEXT_LINE 0x85
46 #define H_TAB_SET 0x88
47 #define REVERSE_INDEX 0x8D
50 #define FIRST_CSI_CMD 0x40
52 /***********************
53 ** writeToConsole() **
54 ***********************/
57 ** SGR is the command with most params: 4
58 ** stegerg: RKRMs say it can have any number of parameters in any order. So instead of 4
59 ** we assume and hope that there will never be more than 16 params :-\
62 #define MAX_COMMAND_PARAMS 16
65 ULONG writeToConsole(struct ConUnit *unit, STRPTR buf, ULONG towrite, struct ConsoleBase *ConsoleDevice)
67 IPTR param_tab[MAX_COMMAND_PARAMS];
69 BYTE command;
70 UBYTE numparams;
71 UBYTE *orig_write_str, *write_str;
72 LONG written, orig_towrite;
74 write_str = orig_write_str = (UBYTE *)buf;
77 EnterFunc(bug("WriteToConsole(ioreq=%p)\n"));
80 orig_towrite = towrite;
82 D(bug("Number of chars to write %d\n", towrite));
85 /* Interpret string into a command and execute command */
87 /* DEBUG aid */
89 #if DEBUG
91 UWORD i;
92 for (i = 0; i < towrite; i ++)
93 kprintf("%x", write_str[i]);
95 kprintf("\n");
98 #endif
99 while (towrite > 0)
101 numparams = 0;
103 if (!string2command(&command, &write_str, &numparams, towrite, param_tab, (Object *)unit, ConsoleDevice))
104 break;
107 Console_DoCommand((Object *)unit, command, numparams, param_tab);
109 towrite = orig_towrite - (write_str - orig_write_str);
111 } /* while (characters left to interpret) */
113 written = write_str - orig_write_str;
115 ReturnInt("WriteToConsole", LONG, written);
119 /**********************
120 ** string2command() **
121 **********************/
124 static const UBYTE str_slm[] = {0x32, 0x30, 0x68 }; /* Set linefeed mode */
125 static const UBYTE str_rnm[] = {0x32, 0x30, 0x6C }; /* Reset linefeed mode */
126 static const UBYTE str_ssm[] = {0x3E, 0x31, 0x68 }; /* Set autoscroll mode */
127 static const UBYTE str_rsm[] = {0x3E, 0x31, 0x6C }; /* Reset autoscroll mode */
128 static const UBYTE str_swm[] = {0x3E, 0x37, 0x68 }; /* Set autowrap mode */
129 static const UBYTE str_rwm[] = {0x3E, 0x37, 0x6C }; /* Reset autowrap mode */
130 static const UBYTE str_dsr[] = {0x36, 0x6E }; /* device status report */
131 static const UBYTE str_con[] = {' ', 'p'}; /* cursor visible */
132 static const UBYTE str_con2[] = {'1', ' ', 'p'}; /* cursor visible */
133 static const UBYTE str_cof[] = {'0', ' ', 'p'}; /* cursor invisible */
135 #define NUM_SPECIAL_COMMANDS 10
136 static const struct special_cmd_descr
138 BYTE Command;
139 STRPTR CommandStr;
140 BYTE Length;
141 } scd_tab[NUM_SPECIAL_COMMANDS] = {
143 {C_SET_LF_MODE, (STRPTR)str_slm, 3 },
144 {C_RESET_LF_MODE, (STRPTR)str_rnm, 3 },
145 {C_SET_AUTOSCROLL_MODE, (STRPTR)str_ssm, 3 },
146 {C_RESET_AUTOSCROLL_MODE, (STRPTR)str_rsm, 3 },
147 {C_SET_AUTOWRAP_MODE, (STRPTR)str_swm, 3 },
148 {C_RESET_AUTOWRAP_MODE, (STRPTR)str_rwm, 3 },
149 {C_DEVICE_STATUS_REPORT, (STRPTR)str_dsr, 2 },
150 {C_CURSOR_VISIBLE, (STRPTR)str_con, 2 },
151 {C_CURSOR_VISIBLE, (STRPTR)str_con2, 3 },
152 {C_CURSOR_INVISIBLE, (STRPTR)str_cof, 3 }
156 #if DEBUG
157 static UBYTE *cmd_names[NUM_CONSOLE_COMMANDS] =
160 "Ascii", /* C_ASCII = 0 */
162 "Esc", /* C_ESC */
163 "Bell", /* C_BELL, */
164 "Backspace", /* C_BACKSPACE, */
165 "HTab", /* C_HTAB, */
166 "Linefeed", /* C_LINEFEED, */
167 "VTab", /* C_VTAB, */
168 "Formefeed", /* C_FORMFEED, */
169 "Carriage return", /* C_CARRIAGE_RETURN, */
170 "Shift In", /* C_SHIFT_IN, */
171 "Shift Out", /* C_SHIFT_OUT, */
172 "Index", /* C_INDEX, */
173 "Nex Line", /* C_NEXT_LINE, */
174 "Tab set", /* C_H_TAB_SET, */
175 "Reverse Idx", /* C_REVERSE_IDX, */
176 "Set LF Mode", /* C_SET_LF_MODE, */
177 "Reset LF Mode", /* C_RESET_lF_MODE, */
178 "Device Status Report", /* C_DEVICE_STATUS_REPORT, */
180 "Insert Char", /* C_INSERT_CHAR, */
181 "Cursor Up", /* C_CURSOR_UP, */
182 "Cursor Down", /* C_CURSOR_DOWN, */
183 "Cursor Forward", /* C_CURSOR_FORWARD, */
184 "Cursor Backward", /* C_CURSOR_BACKWARD, */
185 "Cursor Next Line", /* C_CURSOR_NEXT_LINE, */
186 "Cursor Prev Line", /* C_CURSOR_PREV_LINE, */
187 "Cursor Pos", /* C_CURSOR_POS, */
188 "Cursor HTab", /* C_CURSOR_HTAB, */
189 "Erase In Display", /* C_ERASE_IN_DISPLAY, */
190 "Erase In Line", /* C_ERASE_IN_LINE, */
191 "Insert Line", /* C_INSERT_LINE, */
192 "Delete Line", /* C_DELETE_LINE, */
193 "Delete Char", /* C_DELETE_CHAR, */
194 "Scroll Up", /* C_SCROLL_UP, */
195 "Scroll Down", /* C_SCROLL_DOWN, */
196 "Cursor Tab Ctrl", /* C_CURSOR_TAB_CTRL, */
197 "Cursor Backtab", /* C_CURSOR_BACKTAB, */
198 "Select Graphic Rendition", /* C_SELECT_GRAPHIC_RENDITION */
199 "Cursor Visible", /* C_CURSOR_VISIBLE, */
200 "Cursor Invisible", /* C_CURSOR_INVISIBLE, */
201 "Set Raw Events", /* C_SET_RAWEVENTS, */
202 "Reset Raw Events", /* C_RESET_RAWEVENTS */
203 "Set Auto Wrap Mode", /* C_SET_AUTOWRAP_MODE */
204 "Reset Auto Wrap Mode", /* C_RESET_AUTOWRAP_MODE */
205 "Set Auto Scroll Mode", /* C_SET_AUTOSCROLL_MODE */
206 "Reset Auto Scroll Mode", /* C_RESET_AUTOSCROLL_MODE */
207 "Set Page Length", /* C_SET_PAGE_LENGTH */
208 "Set Line Length", /* C_SET_LINE_LENGTH */
209 "Set Left Offset", /* C_SET_LEFT_OFFSET */
210 "Set Top Offset" /* C_SET_TOP_OFFSET */
212 #endif
214 static BOOL check_special(STRPTR string, LONG toparse)
216 return
218 (*string == CSI) || (toparse >= 2 && (string[0] == ESC) && (string[1] == '[')) || /* CSI */
219 (*string == BELL) ||
220 (*string == BACKSPACE) ||
221 (*string == HTAB) ||
222 (*string == LINEFEED) ||
223 (*string == FORMFEED) ||
224 (*string == CARRIAGE_RETURN) ||
225 (*string == SHIFT_OUT) ||
226 (*string == SHIFT_IN) ||
227 (*string == ESC) ||
228 (*string == INDEX) ||
229 (*string == H_TAB_SET) ||
230 (*string == REVERSE_INDEX)
234 static BOOL string2command( BYTE *cmd_ptr
235 , UBYTE **writestr_ptr
236 , UBYTE *numparams_ptr
237 , LONG toparse
238 , IPTR *p_tab
239 , Object *unit
240 , struct ConsoleBase *ConsoleDevice)
242 UBYTE *write_str = *writestr_ptr;
244 UBYTE *csi_str = write_str;
245 LONG csi_toparse = 0;
247 BOOL found = FALSE,
248 csi = FALSE;
251 EnterFunc(bug("StringToCommand(toparse=%d)\n", toparse));
254 /* Look for <CSI> */
255 if (*write_str == CSI)
258 csi_str ++;
259 csi = TRUE;
260 csi_toparse = toparse - 1;
262 else if (toparse >= 2)
264 if ( (write_str[0] == ESC) && (write_str[1] == '[') )
266 csi_str += 2;
267 csi_toparse = toparse - 2;
268 csi = TRUE;
272 if (csi)
274 D(bug("CSI found, getting command\n"));
276 /* Search for the longest commands first */
278 if (!found)
280 BYTE i;
281 /* Look for some special commands */
282 for (i = 0; ((i < NUM_SPECIAL_COMMANDS) && (!found)) ; i ++ )
284 /* Check whether command sequence is longer than input */
285 if (scd_tab[i].Length > csi_toparse)
286 continue; /* if so, check next command sequence */
288 D(bug("Comparing for special command %d, idx %d, cmdstr %p, len %d, csistr %p \n",
289 scd_tab[i].Command, i, scd_tab[i].CommandStr, scd_tab[i].Length, csi_str));
290 /* Command match ? */
291 if (0 == strncmp(csi_str, scd_tab[i].CommandStr, scd_tab[i].Length))
293 D(bug("Special command found\n"));
294 csi_str += scd_tab[i].Length;
295 *cmd_ptr = scd_tab[i].Command;
297 found = TRUE;
300 } /* for (each special command) */
304 /* A parameter command ? (Ie. one of the commands that takes parameters) */
305 if (!found)
306 found = getparamcommand(cmd_ptr, &csi_str, numparams_ptr, 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 BELL:
318 *cmd_ptr = C_BELL;
319 found = TRUE;
320 break;
322 case BACKSPACE:
323 *cmd_ptr = C_BACKSPACE;
324 found = TRUE;
325 break;
327 case HTAB:
328 *cmd_ptr = C_HTAB;
329 found = TRUE;
330 break;
332 case LINEFEED:
333 *cmd_ptr = C_LINEFEED;
334 found = TRUE;
335 break;
337 case VTAB:
338 *cmd_ptr = C_VTAB;
339 found = TRUE;
340 break;
342 case FORMFEED:
343 *cmd_ptr = C_FORMFEED;
344 found = TRUE;
345 break;
347 case CARRIAGE_RETURN:
348 *cmd_ptr = C_CARRIAGE_RETURN;
349 found = TRUE;
350 break;
352 case SHIFT_OUT:
353 *cmd_ptr = C_SHIFT_OUT;
354 found = TRUE;
355 break;
357 case SHIFT_IN:
358 *cmd_ptr = C_SHIFT_IN;
359 found = TRUE;
360 break;
362 case ESC:
363 *cmd_ptr = C_ESC;
364 found = TRUE;
365 break;
367 case INDEX:
368 *cmd_ptr = C_INDEX;
369 found = TRUE;
370 break;
372 case NEXT_LINE:
373 *cmd_ptr = C_NEXT_LINE;
374 found = TRUE;
375 break;
377 case H_TAB_SET:
378 *cmd_ptr = C_H_TAB_SET;
379 found = TRUE;
380 break;
382 case REVERSE_INDEX:
383 *cmd_ptr = C_REVERSE_IDX;
384 found = TRUE;
385 break;
387 } /* (switch) */
389 if (found)
391 /* Found special char. Increase pointer */
393 write_str ++;
398 if (!found) /* Still not any found ? Try to print as plain ASCII */
400 *cmd_ptr = C_ASCII_STRING;
402 p_tab[0] = (IPTR)write_str;
403 *numparams_ptr = 2;
404 found = TRUE;
408 toparse--;
409 write_str++;
410 } while (toparse && !check_special(write_str, toparse));
412 p_tab[1] = (IPTR)(write_str - (UBYTE *)p_tab[0]); /* store the string length */
415 D(bug("FOUND CMD: %s\n", cmd_names[*cmd_ptr]));
417 /* Return pointer to first character AFTER last interpreted char */
418 *writestr_ptr = write_str;
420 ReturnBool ("StringToCommand", found);
424 /************************
425 ** getparamcommand() **
426 ************************/
428 /* !!! IMPORTANT !!!
429 If you add a command here, you should also add default values for
430 its parameters in Console::GetDefaultParams()
432 static const struct Command
434 BYTE Command;
435 UBYTE MaxParams;
437 } csi2command[] = {
439 { C_INSERT_CHAR , 1 }, /* 0x40 @ */
440 { C_CURSOR_UP , 1 }, /* 0x41 A */
441 { C_CURSOR_DOWN , 1 }, /* 0x42 B */
442 { C_CURSOR_FORWARD , 1 }, /* 0x43 C */
443 { C_CURSOR_BACKWARD , 1 }, /* 0x44 D */
444 { C_CURSOR_NEXT_LINE , 1 }, /* 0x45 E */
445 { C_CURSOR_PREV_LINE , 1 }, /* 0x46 F */
446 { -1 , }, /* 0x47 G */
447 { C_CURSOR_POS , 2 }, /* 0x48 H */
448 { C_CURSOR_HTAB , 1 }, /* 0x49 I */
450 { C_ERASE_IN_DISPLAY , 0 }, /* 0x4A J */
451 { C_ERASE_IN_LINE , 0 }, /* 0x4B K */
452 { C_INSERT_LINE , 0 }, /* 0x4C L */
453 { C_DELETE_LINE , 0 }, /* 0x4D M */
454 { -1 , }, /* 0x4E N */
455 { -1 , }, /* 0x4F O */
456 { C_DELETE_CHAR , 1 }, /* 0x50 P */
457 { -1 , }, /* 0x51 Q */
458 { -1 , }, /* 0x52 R */
459 { C_SCROLL_UP , 1 }, /* 0x53 S */
460 { C_SCROLL_DOWN , 1 }, /* 0x54 T */
461 { -1 , }, /* 0x55 U */
462 { -1 , }, /* 0x56 V */
463 { C_CURSOR_TAB_CTRL , 1 }, /* 0x57 W */
464 { -1 , }, /* 0x58 X */
465 { -1 , }, /* 0x59 Y */
466 { C_CURSOR_BACKTAB , 1 }, /* 0x5A Z */
467 { -1 , }, /* 0x5B [ */
468 { -1 , }, /* 0x5C \ */
469 { -1 , }, /* 0x5D ] */
470 { -1 , }, /* 0x5E ^ */
471 { -1 , }, /* 0x5F _ */
472 { -1 , }, /* 0x60 ` */
473 { -1 , }, /* 0x61 a */
474 { -1 , }, /* 0x62 b */
475 { -1 , }, /* 0x63 c */
476 { -1 , }, /* 0x64 d */
477 { -1 , }, /* 0x65 e */
478 { -1 , }, /* 0x66 f */
479 { -1 , }, /* 0x67 g */
480 { -1 , }, /* 0x68 h */
481 { -1 , }, /* 0x69 i */
482 { -1 , }, /* 0x6A j */
483 { -1 , }, /* 0x6B k */
484 { -1 , }, /* 0x6C l */
485 { C_SELECT_GRAPHIC_RENDITION, MAX_COMMAND_PARAMS }, /* 0x6D m */
486 { -1 , }, /* 0x6E n */
487 { -1 , }, /* 0x6F o */
488 { -1 , }, /* 0x70 p */
489 { -1 , }, /* 0x71 q */
490 { -1 , }, /* 0x72 r */
491 { -1 , }, /* 0x73 s */
492 { C_SET_PAGE_LENGTH , }, /* 0x74 t */
493 { C_SET_LINE_LENGTH , }, /* 0x75 u */
494 { -1 , }, /* 0x76 v */
495 { -1 , }, /* 0x77 w */
496 { C_SET_LEFT_OFFSET , }, /* 0x78 x */
497 { C_SET_TOP_OFFSET , }, /* 0x79 y */
498 { -1 , }, /* 0x7A z */
499 { C_SET_RAWEVENTS , MAX_COMMAND_PARAMS }, /* 0x7B { */
500 { -1 , }, /* 0x7C | */
501 { C_RESET_RAWEVENTS , MAX_COMMAND_PARAMS }, /* 0x7D } */
505 #define PARAM_BUF_SIZE MAX_COMMAND_PARAMS
506 /* Parameters for commands are parsed and filled into this one */
507 struct cmd_params
509 UBYTE numparams; /* Parameters stored */
511 /* Since parameters may be optional, only supplied parameters
512 are saved, along with their number. For example
513 for the command CURSOR POSITION, if only the sencond parameter
514 (column) is specified in the write stream, then
515 numparams will be 1 and for the one entry, paramno will be 1 (C counting)
516 and val will be <column>.
517 Row will have to be set to some default value.
519 struct cmd_param
521 UBYTE paramno; /* Starts counting at 0 */
522 UBYTE val;
523 } tab[PARAM_BUF_SIZE];
527 static BOOL getparamcommand(BYTE *cmd_ptr
528 , UBYTE **writestr_ptr
529 , UBYTE *numparams_ptr
530 , LONG toparse
531 , IPTR *p_tab
532 , 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;
546 BYTE cmd = -1;
547 BYTE cmd_next_idx = 0; /* Index to byte after the command */
549 /* write_str points to first character after <CSI> */
550 UBYTE *write_str = *writestr_ptr;
552 UBYTE num_params = 0;
554 BOOL done = FALSE,
555 found = FALSE;
557 BOOL next_can_be_separator = TRUE,
558 next_can_be_param = TRUE,
559 next_can_be_commandid = TRUE,
560 last_was_param = FALSE;
562 UBYTE num_separators_found = 0;
564 while (!done)
566 /* In case it's a parameter */
568 if (toparse <= 0)
570 done = TRUE;
571 break;
574 switch (*write_str)
576 case 0x40:
577 case 0x41:
578 case 0x42:
579 case 0x43:
580 case 0x44:
581 case 0x45:
582 case 0x46:
583 case 0x48:
584 case 0x49:
586 case 0x4A:
587 case 0x4B:
588 case 0x4C:
589 case 0x4D:
591 case 0x50:
592 case 0x53:
593 case 0x54:
594 case 0x57:
595 case 0x5A:
596 case 0x6D:
597 case 0x74:
598 case 0x75:
599 case 0x78:
600 case 0x79:
601 case 0x7B:
602 case 0x7D:
604 UBYTE idx = *write_str - FIRST_CSI_CMD;
605 UBYTE maxparams = csi2command[idx].MaxParams;
607 if (next_can_be_commandid)
609 #warning Should also do a MinParams compare
610 if (num_params <= maxparams) /* Valid command ? */
613 /* Assure that there are not to many separators in a command */
614 if ((num_separators_found < maxparams)
615 #warning 0-param commands can be moved to special-command-handlin in string2command()
616 || ((num_separators_found == 0) && (maxparams == 0)))
618 cmd = csi2command[idx].Command;
620 /* Save index to where the next command will start */
621 cmd_next_idx = write_str - *writestr_ptr + 1;
623 params.numparams = num_params;
628 done = TRUE;
630 break;
633 case ';': /* parameter separator, skip it */
635 if (!next_can_be_separator)
637 /* Error */
638 done = TRUE;
639 break;
642 next_can_be_separator = FALSE;
643 next_can_be_param = TRUE;
644 next_can_be_commandid = FALSE;
645 last_was_param = FALSE;
647 num_separators_found ++;
649 break;
651 case '0':
652 case '1':
653 case '2':
654 case '3':
655 case '4':
656 case '5':
657 case '6':
658 case '7':
659 case '8':
660 case '9':
661 case '>': /* because of SGR background color param :-( */
662 if (!next_can_be_param)
664 /* Error */
665 done = TRUE;
666 break;
669 if (!last_was_param)
671 num_params++;
672 if (num_params > MAX_COMMAND_PARAMS)
674 done = TRUE;
675 break;
677 params.tab[num_params - 1].paramno = num_params - 1;
678 params.tab[num_params - 1].val = 0;
680 last_was_param = TRUE;
683 params.tab[num_params - 1].val *= 10;
684 if (*write_str == '>')
686 params.tab[num_params - 1].val += 5;
687 } else {
688 params.tab[num_params - 1].val += (*write_str) - '0';
691 next_can_be_separator = TRUE;
692 next_can_be_commandid = TRUE;
693 break;
695 default:
696 /* Error */
697 done = TRUE;
698 break;
700 } /* switch */
703 write_str ++;
704 toparse --;
706 } /* while (!done) */
708 if (cmd != -1)
710 *cmd_ptr = cmd;
711 found = TRUE;
713 /* Continue parsing on the first byte after the command */
714 *writestr_ptr += cmd_next_idx;
717 if (found)
719 UBYTE i;
720 /* First fill in some default values in p_tab */
721 Console_GetDefaultParams(unit, *cmd_ptr, p_tab);
723 for (i = 0; i < params.numparams; i ++)
725 /* Override with parsed values */
726 D(bug("CMD %s: Setting param %d to %d\n"
727 , cmd_names[*cmd_ptr]
728 , params.tab[i].paramno
729 , params.tab[i].val));
731 p_tab[params.tab[i].paramno] = params.tab[i].val;
734 *numparams_ptr = params.numparams;
737 return found;
740 VOID printstring(STRPTR string, ULONG len, struct ConsoleBase *ConsoleDevice)
742 while (len --)
744 kprintf("%d/%c ", *string, *string);
745 string ++;
748 kprintf("\n");