85 |
}; |
}; |
86 |
typedef struct cursor *cursor_t; |
typedef struct cursor *cursor_t; |
87 |
|
|
88 |
|
struct scrolling_region |
89 |
|
{ |
90 |
|
uint32_t top; |
91 |
|
uint32_t bottom; |
92 |
|
}; |
93 |
|
|
94 |
struct parse |
struct parse |
95 |
{ |
{ |
96 |
/* The parsing state of output characters, needed to handle escape |
/* The parsing state of output characters, needed to handle escape |
102 |
STATE_ESC, |
STATE_ESC, |
103 |
STATE_ESC_BRACKET_INIT, |
STATE_ESC_BRACKET_INIT, |
104 |
STATE_ESC_BRACKET, |
STATE_ESC_BRACKET, |
105 |
STATE_ESC_BRACKET_QUESTION |
STATE_ESC_BRACKET_QUESTION, |
106 |
|
STATE_ESC_BRACKET_RIGHT_ANGLE |
107 |
} state; |
} state; |
108 |
|
|
109 |
/* How many parameters an escape sequence may have. */ |
/* How many parameters an escape sequence may have. */ |
178 |
signal for this virtual console. */ |
signal for this virtual console. */ |
179 |
int owner_id; |
int owner_id; |
180 |
|
|
181 |
|
/* The pending changes. */ |
182 |
struct changes changes; |
struct changes changes; |
183 |
|
|
184 |
|
/* The state of the virtual console. */ |
185 |
|
/* The saved cursor position. */ |
186 |
struct cursor cursor; |
struct cursor cursor; |
187 |
|
/* The output queue and parser state. */ |
188 |
struct output output; |
struct output output; |
189 |
|
/* The current video attributes. */ |
190 |
struct attr attr; |
struct attr attr; |
191 |
|
/* Non-zero if we are in insert mode. */ |
192 |
|
int insert_mode; |
193 |
|
/* Scrolling region. */ |
194 |
|
struct scrolling_region csr; |
195 |
|
|
196 |
struct cons_display *user; |
struct cons_display *user; |
197 |
|
|
198 |
struct user_pager_info *upi; |
struct user_pager_info *upi; |
988 |
{ |
{ |
989 |
switch (code) |
switch (code) |
990 |
{ |
{ |
991 |
|
case 4: /* ECMA-48 <SMIR>, <RMIR>. */ |
992 |
|
/* Insert mode: <smir>, <rmir>. */ |
993 |
|
display->insert_mode = flag ? 1 : 0; |
994 |
|
break; |
995 |
case 34: |
case 34: |
996 |
/* Cursor standout: <cnorm>, <cvvis>. */ |
/* Cursor standout: <cnorm>, <cvvis>. */ |
997 |
if (flag) |
if (flag) |
|
display->user->cursor.status = CONS_CURSOR_VERY_VISIBLE; |
|
|
else |
|
998 |
display->user->cursor.status = CONS_CURSOR_NORMAL; |
display->user->cursor.status = CONS_CURSOR_NORMAL; |
999 |
|
else |
1000 |
|
display->user->cursor.status = CONS_CURSOR_VERY_VISIBLE; |
1001 |
/* XXX Flag cursor status change. */ |
/* XXX Flag cursor status change. */ |
1002 |
break; |
break; |
1003 |
} |
} |
1049 |
/* Alternate character set mode on: <smacs>. */ |
/* Alternate character set mode on: <smacs>. */ |
1050 |
attr->altchar = 1; |
attr->altchar = 1; |
1051 |
break; |
break; |
1052 |
|
case 21: |
1053 |
|
/* Normal intensity (switch off bright). */ |
1054 |
|
attr->current.intensity = CONS_ATTR_INTENSITY_NORMAL; |
1055 |
|
break; |
1056 |
case 22: |
case 22: |
1057 |
/* Normal intensity. */ |
/* Normal intensity (switch off dim). */ |
1058 |
attr->current.intensity = CONS_ATTR_INTENSITY_NORMAL; |
attr->current.intensity = CONS_ATTR_INTENSITY_NORMAL; |
1059 |
break; |
break; |
1060 |
case 23: |
case 23: |
1120 |
{ |
{ |
1121 |
struct cons_display *user = display->user; |
struct cons_display *user = display->user; |
1122 |
|
|
1123 |
if (user->cursor.row < user->screen.height - 1) |
if (display->csr.top == 0 && display->csr.bottom >= user->screen.height - 1) |
1124 |
{ |
{ |
1125 |
user->cursor.row++; |
/* No scrolling region active, do the normal scrolling activity. */ |
1126 |
/* XXX Flag cursor update. */ |
if (user->cursor.row < user->screen.height - 1) |
1127 |
|
{ |
1128 |
|
user->cursor.row++; |
1129 |
|
/* XXX Flag cursor update. */ |
1130 |
|
} |
1131 |
|
else |
1132 |
|
{ |
1133 |
|
user->screen.cur_line++; |
1134 |
|
|
1135 |
|
screen_fill (display, 0, user->screen.height - 1, |
1136 |
|
user->screen.width - 1, user->screen.height - 1, |
1137 |
|
L' ', display->attr.current); |
1138 |
|
if (user->screen.scr_lines < |
1139 |
|
user->screen.lines - user->screen.height) |
1140 |
|
user->screen.scr_lines++; |
1141 |
|
/* XXX Flag current line change. */ |
1142 |
|
/* XXX Possibly flag change of length of scroll back buffer. */ |
1143 |
|
} |
1144 |
} |
} |
1145 |
else |
else |
1146 |
{ |
{ |
1147 |
user->screen.cur_line++; |
/* With an active scrolling region, never actually scroll. Just |
1148 |
|
shift the scrolling region if necessary. */ |
1149 |
screen_fill (display, 0, user->screen.height - 1, |
if (user->cursor.row != display->csr.bottom |
1150 |
user->screen.width - 1, user->screen.height - 1, |
&& user->cursor.row < user->screen.height - 1) |
1151 |
L' ', display->attr.current); |
{ |
1152 |
if (user->screen.scr_lines < |
user->cursor.row++; |
1153 |
user->screen.lines - user->screen.height) |
/* XXX Flag cursor update. */ |
1154 |
user->screen.scr_lines++; |
} |
1155 |
/* XXX Flag current line change. */ |
else if (user->cursor.row == display->csr.bottom) |
1156 |
/* XXX Possibly flag change of length of scroll back buffer. */ |
screen_shift_left (display, 0, display->csr.top, |
1157 |
} |
user->screen.width - 1, display->csr.bottom, |
1158 |
|
user->screen.width, |
1159 |
|
L' ', display->attr.current); |
1160 |
|
} |
1161 |
} |
} |
1162 |
|
|
1163 |
static void |
static void |
1237 |
user->cursor.col -= (parse->params[0] ?: 1); |
user->cursor.col -= (parse->params[0] ?: 1); |
1238 |
limit_cursor (display); |
limit_cursor (display); |
1239 |
break; |
break; |
1240 |
case 'h': |
case 'l': |
1241 |
/* Reset mode. */ |
/* Reset mode. */ |
1242 |
for (i = 0; i < parse->nparams; i++) |
for (i = 0; i < parse->nparams; i++) |
1243 |
handle_esc_bracket_hl (display, parse->params[i], 0); |
handle_esc_bracket_hl (display, parse->params[i], 0); |
1244 |
break; |
break; |
1245 |
case 'l': |
case 'h': |
1246 |
/* Set mode. */ |
/* Set mode. */ |
1247 |
for (i = 0; i < parse->nparams; i++) |
for (i = 0; i < parse->nparams; i++) |
1248 |
handle_esc_bracket_hl (display, parse->params[i], 1); |
handle_esc_bracket_hl (display, parse->params[i], 1); |
1325 |
parse->params[0] ?: 1, |
parse->params[0] ?: 1, |
1326 |
L' ', display->attr.current); |
L' ', display->attr.current); |
1327 |
break; |
break; |
1328 |
|
case 'r': /* VT100: Set scrolling region. */ |
1329 |
|
if (!parse->params[1]) |
1330 |
|
{ |
1331 |
|
display->csr.top = 0; |
1332 |
|
display->csr.bottom = user->screen.height - 1; |
1333 |
|
} |
1334 |
|
else |
1335 |
|
{ |
1336 |
|
if (parse->params[1] <= user->screen.height |
1337 |
|
&& parse->params[0] < parse->params[1]) |
1338 |
|
{ |
1339 |
|
display->csr.top = parse->params[0] ? parse->params[0] - 1 : 0; |
1340 |
|
display->csr.bottom = parse->params[1] - 1; |
1341 |
|
user->cursor.col = 0; |
1342 |
|
user->cursor.row = 0; |
1343 |
|
/* XXX Flag cursor change. */ |
1344 |
|
} |
1345 |
|
} |
1346 |
|
break; |
1347 |
case 'S': /* ECMA-48 <SU>. */ |
case 'S': /* ECMA-48 <SU>. */ |
1348 |
/* Scroll up: <ind>, <indn>. */ |
/* Scroll up: <ind>, <indn>. */ |
1349 |
screen_shift_left (display, 0, 0, |
screen_shift_left (display, 0, 0, |
1360 |
break; |
break; |
1361 |
case 'X': /* ECMA-48 <ECH>. */ |
case 'X': /* ECMA-48 <ECH>. */ |
1362 |
/* Erase character(s): <ech>. */ |
/* Erase character(s): <ech>. */ |
1363 |
screen_fill (display, user->cursor.col, user->cursor.row, |
{ |
1364 |
/* XXX limit ? */user->cursor.col + (parse->params[0] ?: 1), |
int col = user->cursor.col; |
1365 |
user->cursor.row, |
if (parse->params[0] - 1 > 0) |
1366 |
L' ', display->attr.current); |
col += parse->params[0] - 1; |
1367 |
|
if (col > user->screen.width - 1) |
1368 |
|
col = user->screen.width - 1; |
1369 |
|
|
1370 |
|
screen_fill (display, user->cursor.col, user->cursor.row, |
1371 |
|
col, user->cursor.row, L' ', display->attr.current); |
1372 |
|
} |
1373 |
break; |
break; |
1374 |
case 'I': /* ECMA-48 <CHT>. */ |
case 'I': /* ECMA-48 <CHT>. */ |
1375 |
/* Horizontal tab. */ |
/* Horizontal tab. */ |
1409 |
} |
} |
1410 |
} |
} |
1411 |
|
|
1412 |
|
|
1413 |
static void |
static void |
1414 |
handle_esc_bracket_question_hl (display_t display, int code, int flag) |
handle_esc_bracket_question_hl (display_t display, int code, int flag) |
1415 |
{ |
{ |
1418 |
case 25: |
case 25: |
1419 |
/* Cursor invisibility: <civis>, <cnorm>. */ |
/* Cursor invisibility: <civis>, <cnorm>. */ |
1420 |
if (flag) |
if (flag) |
|
display->user->cursor.status = CONS_CURSOR_INVISIBLE; |
|
|
else |
|
1421 |
display->user->cursor.status = CONS_CURSOR_NORMAL; |
display->user->cursor.status = CONS_CURSOR_NORMAL; |
1422 |
|
else |
1423 |
|
display->user->cursor.status = CONS_CURSOR_INVISIBLE; |
1424 |
/* XXX Flag cursor status change. */ |
/* XXX Flag cursor status change. */ |
1425 |
break; |
break; |
1426 |
} |
} |
1435 |
int i; |
int i; |
1436 |
switch (op) |
switch (op) |
1437 |
{ |
{ |
1438 |
case 'h': |
case 'l': |
1439 |
/* Reset mode. */ |
/* Reset mode. */ |
1440 |
for (i = 0; i < parse->nparams; ++i) |
for (i = 0; i < parse->nparams; ++i) |
1441 |
handle_esc_bracket_question_hl (display, parse->params[i], 0); |
handle_esc_bracket_question_hl (display, parse->params[i], 0); |
1442 |
break; |
break; |
1443 |
case 'l': |
case 'h': |
1444 |
/* Set mode. */ |
/* Set mode. */ |
1445 |
for (i = 0; i < parse->nparams; ++i) |
for (i = 0; i < parse->nparams; ++i) |
1446 |
handle_esc_bracket_question_hl (display, parse->params[i], 1); |
handle_esc_bracket_question_hl (display, parse->params[i], 1); |
1448 |
} |
} |
1449 |
} |
} |
1450 |
|
|
1451 |
|
|
1452 |
|
static void |
1453 |
|
handle_esc_bracket_right_angle_hl (display_t display, int code, int flag) |
1454 |
|
{ |
1455 |
|
switch (code) |
1456 |
|
{ |
1457 |
|
case 1: |
1458 |
|
/* Bold: <gsbom>, <grbom>. This is a GNU extension. */ |
1459 |
|
if (flag) |
1460 |
|
display->attr.current.bold = 1; |
1461 |
|
else |
1462 |
|
display->attr.current.bold = 0; |
1463 |
|
break; |
1464 |
|
} |
1465 |
|
} |
1466 |
|
|
1467 |
|
|
1468 |
|
static void |
1469 |
|
handle_esc_bracket_right_angle (display_t display, char op) |
1470 |
|
{ |
1471 |
|
parse_t parse = &display->output.parse; |
1472 |
|
|
1473 |
|
int i; |
1474 |
|
switch (op) |
1475 |
|
{ |
1476 |
|
case 'l': |
1477 |
|
/* Reset mode. */ |
1478 |
|
for (i = 0; i < parse->nparams; ++i) |
1479 |
|
handle_esc_bracket_right_angle_hl (display, parse->params[i], 0); |
1480 |
|
break; |
1481 |
|
case 'h': |
1482 |
|
/* Set mode. */ |
1483 |
|
for (i = 0; i < parse->nparams; ++i) |
1484 |
|
handle_esc_bracket_right_angle_hl (display, parse->params[i], 1); |
1485 |
|
break; |
1486 |
|
} |
1487 |
|
} |
1488 |
|
|
1489 |
|
|
1490 |
static wchar_t |
static wchar_t |
1491 |
altchar_to_ucs4 (wchar_t chr) |
altchar_to_ucs4 (wchar_t chr) |
1492 |
{ |
{ |
1594 |
user->cursor.col--; |
user->cursor.col--; |
1595 |
else |
else |
1596 |
{ |
{ |
1597 |
/* XXX This implements the <bw> functionality. |
/* This implements the <bw> functionality. */ |
|
The alternative is to cut off and set col to 0. */ |
|
1598 |
user->cursor.col = user->screen.width - 1; |
user->cursor.col = user->screen.width - 1; |
1599 |
user->cursor.row--; |
user->cursor.row--; |
1600 |
} |
} |
1621 |
% user->screen.lines; |
% user->screen.lines; |
1622 |
int idx = line * user->screen.width + user->cursor.col; |
int idx = line * user->screen.width + user->cursor.col; |
1623 |
|
|
1624 |
|
if (display->insert_mode |
1625 |
|
&& user->cursor.col != user->screen.width - 1) |
1626 |
|
{ |
1627 |
|
/* If in insert mode, do the same as <ich1>. */ |
1628 |
|
screen_shift_right (display, user->cursor.col, user->cursor.row, |
1629 |
|
user->screen.width - 1, user->cursor.row, 1, |
1630 |
|
L' ', display->attr.current); |
1631 |
|
} |
1632 |
|
|
1633 |
user->_matrix[idx].chr = display->attr.altchar |
user->_matrix[idx].chr = display->attr.altchar |
1634 |
? altchar_to_ucs4 (chr) : chr; |
? altchar_to_ucs4 (chr) : chr; |
1635 |
user->_matrix[idx].attr = display->attr.current; |
user->_matrix[idx].attr = display->attr.current; |
1657 |
/* Reset: <rs2>. */ |
/* Reset: <rs2>. */ |
1658 |
display->attr.current = display->attr.attr_def; |
display->attr.current = display->attr.attr_def; |
1659 |
display->attr.altchar = 0; |
display->attr.altchar = 0; |
1660 |
|
display->insert_mode = 0; |
1661 |
|
display->csr.top = 0; |
1662 |
|
display->csr.bottom = user->screen.height - 1; |
1663 |
user->cursor.status = CONS_CURSOR_NORMAL; |
user->cursor.status = CONS_CURSOR_NORMAL; |
1664 |
/* Fall through. */ |
/* Fall through. */ |
1665 |
case L'c': |
case L'c': |
1691 |
/* Visible bell. */ |
/* Visible bell. */ |
1692 |
user->bell.visible++; |
user->bell.visible++; |
1693 |
break; |
break; |
|
case L'Q': /* ECMA-48 <PU1>. */ |
|
|
/* Bold on: <gsbom>. This is a GNU extension. */ |
|
|
display->attr.current.bold = 1; |
|
|
break; |
|
|
case L'R': /* ECMA-48 <PU2>. */ |
|
|
/* Bold off: <grbom>. This is a GNU extension. */ |
|
|
display->attr.current.bold = 0; |
|
|
break; |
|
1694 |
default: |
default: |
1695 |
/* Unsupported escape sequence. */ |
/* Unsupported escape sequence. */ |
1696 |
break; |
break; |
1705 |
parse->state = STATE_ESC_BRACKET_QUESTION; |
parse->state = STATE_ESC_BRACKET_QUESTION; |
1706 |
break; /* Consume the question mark. */ |
break; /* Consume the question mark. */ |
1707 |
} |
} |
1708 |
|
else if (chr == '>') |
1709 |
|
{ |
1710 |
|
parse->state = STATE_ESC_BRACKET_RIGHT_ANGLE; |
1711 |
|
break; /* Consume the right angle. */ |
1712 |
|
} |
1713 |
else |
else |
1714 |
parse->state = STATE_ESC_BRACKET; |
parse->state = STATE_ESC_BRACKET; |
1715 |
/* Fall through. */ |
/* Fall through. */ |
1716 |
case STATE_ESC_BRACKET: |
case STATE_ESC_BRACKET: |
1717 |
case STATE_ESC_BRACKET_QUESTION: |
case STATE_ESC_BRACKET_QUESTION: |
1718 |
|
case STATE_ESC_BRACKET_RIGHT_ANGLE: |
1719 |
if (chr >= '0' && chr <= '9') |
if (chr >= '0' && chr <= '9') |
1720 |
parse->params[parse->nparams] |
parse->params[parse->nparams] |
1721 |
= parse->params[parse->nparams]*10 + chr - '0'; |
= parse->params[parse->nparams]*10 + chr - '0'; |
1729 |
parse->nparams++; |
parse->nparams++; |
1730 |
if (parse->state == STATE_ESC_BRACKET) |
if (parse->state == STATE_ESC_BRACKET) |
1731 |
handle_esc_bracket (display, chr); |
handle_esc_bracket (display, chr); |
1732 |
|
else if (parse->state == STATE_ESC_BRACKET_RIGHT_ANGLE) |
1733 |
|
handle_esc_bracket_right_angle (display, chr); |
1734 |
else |
else |
1735 |
handle_esc_bracket_question (display, chr); |
handle_esc_bracket_question (display, chr); |
1736 |
parse->state = STATE_NORMAL; |
parse->state = STATE_NORMAL; |
1859 |
mutex_init (&display->lock); |
mutex_init (&display->lock); |
1860 |
display->attr.attr_def = def_attr; |
display->attr.attr_def = def_attr; |
1861 |
display->attr.current = display->attr.attr_def; |
display->attr.current = display->attr.attr_def; |
1862 |
|
display->csr.bottom = height - 1; |
1863 |
|
|
1864 |
err = user_create (display, width, height, lines, L' ', |
err = user_create (display, width, height, lines, L' ', |
1865 |
display->attr.current); |
display->attr.current); |
1866 |
if (err) |
if (err) |
2042 |
errno = err; |
errno = err; |
2043 |
return err; |
return err; |
2044 |
} |
} |
|
/* XXX What should be done with invalid characters etc? */ |
|
2045 |
if (buffer_size) |
if (buffer_size) |
2046 |
{ |
{ |
2047 |
/* If we used the caller's buffer DATA, the remaining bytes |
/* If we used the caller's buffer DATA, the remaining bytes |