#include "clib.h"
#include "i386.h"
#include "console.h"
/*
* implementazione console virtuali.
* la procedura di print riconosce molte delle sequenze escape utilizzate
* dal driver ansi.sys del dos.
* che sono :
*
* e[x;yH posiziona cursore x,y
* e[x;yf idem
* e[nA cursore in alto di n char
* e[nB cursore in basso di n char
* e[nC cursore avanti n char
* e[nD cursore indietro n char
* e[s salva posizione cursore
* e[u ripristina posizione salvata
* e[2J cancella schermo, e mette il cursore in (0,0)
* e[K cancella riga
* e[n;...;nm imposta colori di primo piano e sfondo, ed il blink:
* 5:attiva blink 0: disattiva blink
* Colori in primo piano
* 30 Nero
* 31 Rosso
* 32 Verde
* 33 Giallo
* 34 Blu
* 35 Magenta
* 36 Azzurro
* 37 Bianco
*
* Colori di sfondo = primo piano+10
*
* NB: c->width deve essere <= c->hwwidth !!
*/
char sc2ascii[128] =
{
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 8, 9, /* 0 */
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 13, 0, 'a', 's', /* 1 */
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 39, '`', 0, 92, 'z', 'x', 'c', 'v', /* 2 */
'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 8, /* 3 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0, 0, '+', 0, /* 4 */
0, 0, 0, 127, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
0, 0, '/', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, /* 6 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 7 */
};
char ssc2ascii[128] =
{
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
0, 27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 8, 9, /* 0 */
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 13, 0, 'A', 'S', /* 1 */
'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', 34, '~', 0, '|', 'Z', 'X', 'C', 'V', /* 2 */
'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, /* 3 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0, 0, '+', 0, /* 4 */
0, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
0, 0, '/', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, /* 6 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 7 */
};
/* stampa una stringa "cosi` com'e`", NESSUN carattere viene interpretato */
static
int printraw(console_t *c, const char *str, int max_len)
{
int l = 0;
if (max_len < 0) max_len = strlen(str);
/*
* FIXME: questo loop si puo` ottimizzare un tot, evitando il check
* per c->cY, ed anche la moltiplicazione
*/
while (l < max_len && *str) {
if (c->cX >= c->width) {
c->cY++;
c->cX = 0;
}
if (c->cY >= c->height) {
memmove(&c->video[0], &c->video[c->width*(c->cY - c->height+1)], (c->width-1)*c->height*2);
c->cY = c->height-1;
}
c->video[c->cX+c->cY*c->width] = *str + c->color;
c->cX++;
str++;
l++;
}
return l;
}
/* gestisce le sequenze escape con parametri */
static
const char* do_escape2(console_t *c, const char *s)
{
const char *end = s;
int i = 0;
int j;
int nums[5];
do {
nums[i] = strtoul(s, (char**)&end, 0);
if (s != end) i++;
s = end+1;
} while ((*end == ';') && (i < 5));
switch (*end) {
case 'H':
case 'f': /* posiziona cursore */
if (i == 0) {
c->cX = c->cY = 0;
return end+1;
} else if (i == 2) {
if (nums[0] < c->width) c->cX = nums[0];
if (nums[1] < c->height) c->cY = nums[1];
return end+1;
}
return end;
case 'A': /* Y-- */
j = c->cY;
j-= nums[0];
if (j > 0 && j < c->height) c->cY = j;
return end+1;
case 'B': /* Y++ */
j = c->cY;
j+= nums[0];
if (j > 0 && j < c->height) c->cY = j;
return end+1;
case 'C': /* X++ */
j = c->cX;
j+= nums[0];
if (j > 0 && j < c->width) c->cX = j;
return end+1;
case 'D': /* X-- */
j = c->cX;
j-= nums[0];
if (j > 0 && j < c->width) c->cX = j;
return end+1;
case 'm':
{
char fgc[] = {0,4,2,14,1,5,9,15};
char bgc[] = {0,4,2,6,1,5,3,7};
for (j=0; j < i; j++) {
switch (nums[j]) {
case 0: /* disattiva attributi */
c->color &= ~0x8000;
break;
case 5: /* attiva blink */
c->color |= 0x8000;
break;
case 30 ... 37:
/* imposta colore primo piano */
c->color &= 0xF000;
c->color |= fgc[nums[j] - 30] << 8;
break;
case 40 ... 47:
/* imposta colore sfondo */
c->color &= 0x8F00;
c->color |= bgc[nums[j] - 40] << 12;
break;
default: break;
}
}
return end+1;
}
case 'p':
/* questa e` la definizione dei tasti */
return end+1;
default: return end;
}
}
/* gestisce caratteri escape semplici */
static
const char* do_escape(console_t *c, const char *s)
{
switch (*s) {
case 'K':
/* cancella riga dalla posizione del cursore compresa */
memset(&c->video[c->cY*c->width+c->cX], 0, (c->width-c->cX)*2);
return s+1;
case 'u':
/* ripristina posizione salvata */
c->cX = c->savX;
c->cY = c->savY;
return s+1;
case 's':
/* salva posizione cursore */
c->savX = c->cX;
c->savY = c->cY;
return s+1;
case '2': // '2J'
/* cancella schermo */
if (s[1] == 'J') {
/* clrscr */
memset(&c->video[0], 0, c->width*c->height*2);
c->cX = c->cY = 0;
return s+2;
}
return s;
default: return do_escape2(c, s);
}
}
/* procedura di print con riconoscimento dei caratteri escape
NB: tutti i caratteri ascii < 32 se non riconosciuti validi
sono ignorati
*/
static
int print(console_t *c, const char *str)
{
const char* last = str;
int r = 0;
while (*str) {
if (*str < 32) {
r += printraw(c, last, str - last);
switch (*str) {
case '\a': /* bell 07 */
break;
case '\b': /* backspace 08 */
c->cX--;
break;
case '\f': /* from feed 12 */
c->cX = 0;
break;
case '\n': /* line feed 10 */
c->cX = 0;
c->cY++;
break;
case '\t': /* tab 09 */
c->cX += c->fl.htabsize;
break;
case '\e': /* escape 27 */
if (str[1] == '[' && str[2] != '\0')
str = do_escape(c, &str[2]) -1;
break;
case '\v': /* vertical tab 11 */
c->cY+= c->fl.vtabsize;
break;
case '\r': /* 13 */
c->cY++;
break;
default: break;
}
last = ++str;
} else str++;
}
return r+printraw(c, last, -1);
}
/*
* procedura di print, ritorna il numero di caratteri stampati
*
*/
int con_write(console_t* c, const char *str)
{
int n;
try_again:
;
asm_cli;
if (c->fl.outrdy) {
c->fl.outrdy = 0;
asm_sti;
if (c->fl.rawout) n = printraw(c,str,-1);
else n = print(c, str);
if (c->fl.movecursor) {
unsigned i = c->hwwidth*c->cY+c->cX;
outportb(0x3D4, 0xF);
outportb(0x3D5, (byte)i);
outportb(0x3D4, 0xE);
outportb(0x3D5, i shr 8);
}
if ((c->video[c->cX+c->cY*c->width] shr 8) == 0) {
c->video[c->cX+c->cY*c->width] |= c->color;
}
c->fl.outrdy = 1;
return n;
} else {
/* wait */
goto try_again;
}
}
/* inserisce un carattere nel buffer, se il buffer e` pieno, viene ignorato*/
static
char_t insert_char_t(console_t*c, char_t curc, int sc)
{
char_t* cbuf;
int j;
j = (c->kbstart+1) & 0xF;
if (j == c->kbend) return curc; // full
c->kbstart = j;
cbuf = &c->keybuf[j];
curc.scanc = sc;
if (c->shift.shift || c->shift.capslock)
curc.ascii = ssc2ascii[sc];
else curc.ascii = sc2ascii[sc];
if (c->shift.shift) curc.shift = 1;
if (c->shift.alt) curc.alt = 1;
if (c->shift.ctrl) curc.ctrl = 1;
if (c->shift.capslock) curc.capslock = 1;
if (c->shift.numlock) curc.numlock = 1;
if (c->prev.scanc = 0xE0) curc.extended = 1;
return *cbuf = curc;
}
char_t con_get_key(console_t* c)
{
char_t r;
*(int*)&r = 0;
asm_cli;
if (c->kbstart != c->kbend) {
c->kbend = (c->kbend +1) & 0x0F;
r = c->keybuf[c->kbend];
}
asm_sti;
return r;
}
void con_convert_key(console_t* c, int sc)
{
char_t curc;
char_t prevshift = c->shift;
*(int*)&curc = 0;
if (c->fl.rawin) {
c->prev = insert_char_t(c, curc, sc);
return;
}
if (sc >= 0x80) {
/* tasto rilasciato */
if (sc == 0xE0) {
/* codice esteso */
c->prev.scanc = 0xE0;
return;
}
switch (sc & 0x7F) {
case 0x1D: /* ctrl */
c->shift.ctrl = 0;
break;
case 0x2A: /* Lshift */
c->shift.shift = 0;
break;
case 0x36: /* Rshift */
c->shift.shift = 0;
break;
case 0x38: /* alt */
c->shift.alt = 0;
break;
case 0x3A: /* caps */
c->shift.capslock = 0;
break;
case 0x45: /* num */
c->shift.numlock = 0;
break;
case 0x46: /* scroll */
c->shift.scrollock = 0;
break;
case 0x52: /* ins */
c->shift.insert = 0;
break;
}
if (c->fl.want_released) {
curc.released = 1;
c->prev = insert_char_t(c, curc, sc);
} else {
curc.scanc = sc;
c->prev = curc;
}
} else {
switch (sc) {
case 0x1D: /* ctrl */
c->shift.ctrl = 1;
break;
case 0x2A: /* Lshift */
c->shift.shift = 1;
break;
case 0x36: /* Rshift */
c->shift.shift = 1;
break;
case 0x38: /* alt */
c->shift.alt = 1;
break;
case 0x3A: /* caps */
c->shift.capslock = 1;
break;
case 0x45: /* num */
c->shift.numlock = 1;
break;
case 0x46: /* scroll */
c->shift.scrollock = 1;
break;
case 0x52: /* ins */
c->shift.insert = 1;
break;
}
c->prev = insert_char_t(c, curc, sc);
}
if (*(int*)&c->shift != *(int*)&prevshift) {
/* mettere a posto i leds */
}
}