This repository has been archived on 2023-08-20. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
RescueBootCD/extra/syslinux-3.09/com32/lib/sys/ansicon_write.c

539 lines
11 KiB
C

#ident "$Id: ansicon_write.c,v 1.9 2005/01/05 07:45:23 hpa Exp $"
/* ----------------------------------------------------------------------- *
*
* Copyright 2004 H. Peter Anvin - All Rights Reserved
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall
* be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* ----------------------------------------------------------------------- */
/*
* ansicon_write.c
*
* Write to the screen using ANSI control codes (about as capable as
* DOS' ANSI.SYS.)
*/
#include <errno.h>
#include <string.h>
#include <com32.h>
#include <minmax.h>
#include <klibc/compiler.h>
#include "file.h"
struct curxy {
uint8_t x, y;
} __attribute__((packed));
#define BIOS_CURXY ((struct curxy *)0x450) /* Array for each page */
#define BIOS_ROWS (*(uint8_t *)0x484) /* Minus one; if zero use 24 (= 25 lines) */
#define BIOS_COLS (*(uint16_t *)0x44A)
#define BIOS_PAGE (*(uint8_t *)0x462)
enum ansi_state {
st_init, /* Normal (no ESC seen) */
st_esc, /* ESC seen */
st_csi, /* CSI seen */
};
#define MAX_PARMS 16
struct term_state {
int disabled;
int attr; /* Current display attribute */
int vtgraphics; /* VT graphics on/off */
int intensity;
int underline;
int blink;
int reverse;
int fg;
int bg;
int autocr;
struct curxy saved_xy;
uint16_t cursor_type;
enum ansi_state state;
int pvt; /* Private code? */
int nparms; /* Number of parameters seen */
int parms[MAX_PARMS];
};
static const struct term_state default_state =
{
.disabled = 0,
.attr = 0x07, /* Grey on black */
.vtgraphics = 0,
.intensity = 1,
.underline = 0,
.blink = 0,
.reverse = 0,
.fg = 7,
.bg = 0,
.autocr = 0,
.saved_xy = { 0, 0 },
.cursor_type = 0x0607,
.state = st_init,
.pvt = 0,
.nparms = 0,
};
static struct term_state st;
/* DEC VT graphics to codepage 437 table (characters 0x60-0x7F only) */
static const char decvt_to_cp437[] =
{ 0004, 0261, 0007, 0007, 0007, 0007, 0370, 0361, 0007, 0007, 0331, 0277, 0332, 0300, 0305, 0304,
0304, 0304, 0137, 0137, 0303, 0264, 0301, 0302, 0263, 0363, 0362, 0343, 0330, 0234, 0007, 00 };
/* Common setup */
static void __constructor ansicon_init(void)
{
static com32sys_t ireg; /* Auto-initalized to all zero */
com32sys_t oreg;
/* Initial state */
memcpy(&st, &default_state, sizeof st);
/* Are we disabled? */
ireg.eax.w[0] = 0x000b;
__intcall(0x22, &ireg, &oreg);
if ( (signed char)oreg.ebx.b[1] < 0 ) {
st.disabled = 1;
return;
}
/* Force text mode */
ireg.eax.w[0] = 0x0005;
__intcall(0x22, &ireg, NULL);
/* Get cursor shape */
ireg.eax.b[1] = 0x03;
ireg.ebx.b[1] = BIOS_PAGE;
__intcall(0x10, &ireg, &oreg);
st.cursor_type = oreg.ecx.w[0];
}
/* Erase a region of the screen */
static void ansicon_erase(int x0, int y0, int x1, int y1)
{
static com32sys_t ireg;
ireg.eax.w[0] = 0x0600; /* Clear window */
ireg.ebx.b[1] = st.attr; /* Fill with current attribute */
ireg.ecx.b[0] = x0;
ireg.ecx.b[1] = y0;
ireg.edx.b[0] = x1;
ireg.edx.b[1] = y1;
__intcall(0x10, &ireg, NULL);
}
/* Show or hide the cursor */
static void showcursor(int yes)
{
static com32sys_t ireg;
ireg.eax.b[1] = 0x01;
ireg.ecx.w[0] = yes ? st.cursor_type : 0x2020;
__intcall(0x10, &ireg, NULL);
}
static void ansicon_putchar(int ch)
{
static com32sys_t ireg;
const int rows = BIOS_ROWS ? BIOS_ROWS+1 : 25;
const int cols = BIOS_COLS;
const int page = BIOS_PAGE;
struct curxy xy = BIOS_CURXY[page];
switch ( st.state ) {
case st_init:
switch ( ch ) {
case '\b':
if ( xy.x > 0 ) xy.x--;
break;
case '\t':
{
int nsp = 8 - (xy.x & 7);
while ( nsp-- )
ansicon_putchar(' ');
}
return; /* Cursor already updated */
case '\n':
case '\v':
case '\f':
xy.y++;
if ( st.autocr )
xy.x = 0;
break;
case '\r':
xy.x = 0;
break;
case 127:
/* Ignore delete */
break;
case 14:
st.vtgraphics = 1;
break;
case 15:
st.vtgraphics = 0;
break;
case 27:
st.state = st_esc;
break;
default:
/* Print character */
if ( ch >= 32 ) {
if ( st.vtgraphics && (ch & 0xe0) == 0x60 )
ch = decvt_to_cp437[ch - 0x60];
ireg.eax.b[1] = 0x09;
ireg.eax.b[0] = ch;
ireg.ebx.b[1] = page;
ireg.ebx.b[0] = st.attr;
ireg.ecx.w[0] = 1;
__intcall(0x10, &ireg, NULL);
xy.x++;
}
break;
}
break;
case st_esc:
switch ( ch ) {
case '%':
case '(':
case ')':
case '#':
/* Ignore this plus the subsequent character, allows
compatibility with Linux sequence to set charset */
break;
case '[':
st.state = st_csi;
st.nparms = st.pvt = 0;
memset(st.parms, 0, sizeof st.parms);
break;
case 'c':
/* Reset terminal */
memcpy(&st, &default_state, sizeof st);
ansicon_erase(0, 0, cols-1, rows-1);
xy.x = xy.y = 1;
break;
default:
/* Ignore sequence */
st.state = st_init;
break;
}
break;
case st_csi:
{
int p0 = st.parms[0] ? st.parms[0] : 1;
if ( ch >= '0' && ch <= '9' ) {
st.parms[st.nparms] = st.parms[st.nparms]*10 + (ch-'0');
} else if ( ch == ';' ) {
st.nparms++;
if ( st.nparms >= MAX_PARMS )
st.nparms = MAX_PARMS-1;
break;
} else if ( ch == '?' ) {
st.pvt = 1;
} else {
switch ( ch ) {
case 'A':
{
int y = xy.y - p0;
xy.y = (y < 0) ? 0 : y;
}
break;
case 'B':
{
int y = xy.y + p0;
xy.y = (y >= rows) ? rows-1 : y;
}
break;
case 'C':
{
int x = xy.x + p0;
xy.x = (x >= cols) ? cols-1 : x;
}
break;
case 'D':
{
int x = xy.x - p0;
xy.x = (x < 0) ? 0 : x;
}
break;
case 'E':
{
int y = xy.y + p0;
xy.y = (y >= rows) ? rows-1 : y;
xy.x = 0;
}
break;
case 'F':
{
int y = xy.y - p0;
xy.y = (y < 0) ? 0 : y;
xy.x = 0;
}
break;
case 'G':
case '\'':
{
int x = st.parms[0] - 1;
xy.x = (x >= cols) ? cols-1 : (x < 0) ? 0 : x;
}
break;
case 'H':
case 'f':
{
int y = st.parms[0] - 1;
int x = st.parms[1] - 1;
xy.x = (x >= cols) ? cols-1 : (x < 0) ? 0 : x;
xy.y = (y >= rows) ? rows-1 : (y < 0) ? 0 : y;
}
break;
case 'J':
{
switch ( st.parms[0] ) {
case 0:
ansicon_erase(xy.x, xy.y, cols-1, xy.y);
if ( xy.y < rows-1 )
ansicon_erase(0, xy.y+1, cols-1, rows-1);
break;
case 1:
if ( xy.y > 0 )
ansicon_erase(0, 0, cols-1, xy.y-1);
if ( xy.y > 0 )
ansicon_erase(0, xy.y, xy.x-1, xy.y);
break;
case 2:
ansicon_erase(0, 0, cols-1, rows-1);
break;
default:
/* Ignore */
break;
}
}
break;
case 'K':
{
switch ( st.parms[0] ) {
case 0:
ansicon_erase(xy.x, xy.y, cols-1, xy.y);
break;
case 1:
if ( xy.x > 0 )
ansicon_erase(0, xy.y, xy.x-1, xy.y);
break;
case 2:
ansicon_erase(0, xy.y, cols-1, xy.y);
break;
default:
/* Ignore */
break;
}
}
break;
case 'h':
case 'l':
{
int set = (ch == 'h');
switch ( st.parms[0] ) {
case 20:
st.autocr = set;
break;
case 25:
showcursor(set);
break;
default:
/* Ignore */
break;
}
}
break;
case 'm':
{
static const int ansi2pc[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
int i;
for ( i = 0 ; i <= st.nparms ; i++ ) {
int a = st.parms[i];
switch ( a ) {
case 0:
st.fg = 7;
st.bg = 0;
st.intensity = 1;
st.underline = 0;
st.blink = 0;
st.reverse = 0;
break;
case 1:
st.intensity = 2;
break;
case 2:
st.intensity = 0;
break;
case 4:
st.underline = 1;
break;
case 5:
st.blink = 1;
break;
case 7:
st.reverse = 1;
break;
case 21:
case 22:
st.intensity = 1;
break;
case 24:
st.underline = 0;
break;
case 25:
st.blink = 0;
break;
case 27:
st.reverse = 0;
break;
case 30 ... 37:
st.fg = ansi2pc[a-30];
break;
case 38:
st.fg = 7;
st.underline = 1;
break;
case 39:
st.fg = 7;
st.underline = 0;
break;
case 40 ... 47:
st.bg = ansi2pc[a-40];
break;
case 49:
st.bg = 7;
break;
default:
/* Do nothing */
break;
}
}
/* Turn into an attribute code */
{
int bg = st.bg;
int fg;
if ( st.underline )
fg = 0x01;
else if ( st.intensity == 0 )
fg = 0x08;
else
fg = st.fg;
if ( st.reverse ) {
bg = fg & 0x07;
fg &= 0x08;
fg |= st.bg;
}
if ( st.blink )
bg ^= 0x08;
if ( st.intensity == 2 )
fg ^= 0x08;
st.attr = (bg << 4) | fg;
}
}
break;
case 's':
st.saved_xy = xy;
break;
case 'u':
xy = st.saved_xy;
break;
default: /* Includes CAN and SUB */
break; /* Drop unknown sequence */
}
st.state = st_init;
}
}
break;
}
/* If we fell off the end of the screen, adjust */
if ( xy.x >= cols ) {
xy.x = 0;
xy.y++;
}
while ( xy.y >= rows ) {
xy.y--;
ireg.eax.w[0] = 0x0601;
ireg.ebx.b[1] = st.attr;
ireg.ecx.w[0] = 0;
ireg.edx.b[1] = rows-1;
ireg.edx.b[0] = cols-1;
__intcall(0x10, &ireg, NULL); /* Scroll */
}
/* Update cursor position */
ireg.eax.b[1] = 0x02;
ireg.ebx.b[1] = page;
ireg.edx.b[1] = xy.y;
ireg.edx.b[0] = xy.x;
__intcall(0x10, &ireg, NULL);
}
ssize_t __ansicon_write(struct file_info *fp, const void *buf, size_t count)
{
const unsigned char *bufp = buf;
size_t n = 0;
(void)fp;
if ( st.disabled )
return n; /* Nothing to do */
while ( count-- ) {
ansicon_putchar(*bufp++);
n++;
}
return n;
}
const struct output_dev dev_ansicon_w = {
.dev_magic = __DEV_MAGIC,
.flags = __DEV_TTY | __DEV_OUTPUT,
.fileflags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND,
.write = __ansicon_write,
.close = NULL,
};