413 lines
9.8 KiB
C
413 lines
9.8 KiB
C
/* $NetBSD: wscons_emul.c,v 1.13 1997/10/27 01:37:33 thorpej Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1995, 1996 Carnegie-Mellon University.
|
|
* All rights reserved.
|
|
*
|
|
* Author: Chris G. Demetriou
|
|
*
|
|
* Permission to use, copy, modify and distribute this software and
|
|
* its documentation is hereby granted, provided that both the copyright
|
|
* notice and this permission notice appear in all copies of the
|
|
* software, derivative works or modified versions, and any portions
|
|
* thereof, and that both notices appear in supporting documentation.
|
|
*
|
|
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
|
|
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
|
|
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
|
*
|
|
* Carnegie Mellon requests users of this software to return to
|
|
*
|
|
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
|
|
* School of Computer Science
|
|
* Carnegie Mellon University
|
|
* Pittsburgh PA 15213-3890
|
|
*
|
|
* any improvements or extensions that they make and grant Carnegie the
|
|
* rights to redistribute these changes.
|
|
*/
|
|
|
|
/*
|
|
* Console emulator for a 'generic' ANSI X3.64 console.
|
|
*/
|
|
|
|
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
|
|
|
|
__KERNEL_RCSID(0, "$NetBSD: wscons_emul.c,v 1.13 1997/10/27 01:37:33 thorpej Exp $");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <alpha/wscons/wsconsvar.h>
|
|
#include <alpha/wscons/wscons_emul.h>
|
|
#include <alpha/wscons/ascii.h>
|
|
|
|
static int wscons_emul_input_normal __P((struct wscons_emul_data *, char));
|
|
static int wscons_emul_input_haveesc __P((struct wscons_emul_data *, char));
|
|
static void wscons_emul_docontrol __P((struct wscons_emul_data *, char));
|
|
static int wscons_emul_input_control __P((struct wscons_emul_data *, char));
|
|
|
|
void
|
|
wscons_emul_attach(we, wo)
|
|
struct wscons_emul_data *we;
|
|
const struct wscons_odev_spec *wo;
|
|
{
|
|
int i;
|
|
|
|
#ifdef DIAGNOSTIC
|
|
if (we == NULL || wo == NULL)
|
|
panic("wscons_emul_attach: bogus args");
|
|
if (wo->wo_emulfuncs == NULL)
|
|
panic("wscons_emul_attach: bogus emul functions");
|
|
#endif
|
|
if (wo->wo_nrows <= 0 || wo->wo_ncols <= 0)
|
|
panic("wscons_emul_attach: bogus size (%d/%d)",
|
|
wo->wo_nrows, wo->wo_ncols);
|
|
if (wo->wo_crow < 0 || wo->wo_ccol < 0 ||
|
|
wo->wo_crow >= wo->wo_nrows || wo->wo_ccol >= wo->wo_ncols)
|
|
panic("wscons_emul_attach: bogus location (n: %d/%d, c: %d/%d",
|
|
wo->wo_nrows, wo->wo_ncols, wo->wo_crow, wo->wo_ccol);
|
|
|
|
we->ac_state = ANSICONS_STATE_NORMAL;
|
|
we->ac_ef = wo->wo_emulfuncs;
|
|
we->ac_efa = wo->wo_emulfuncs_cookie;
|
|
|
|
we->ac_nrow = wo->wo_nrows;
|
|
we->ac_ncol = wo->wo_ncols;
|
|
|
|
we->ac_crow = wo->wo_crow;
|
|
we->ac_ccol = wo->wo_ccol;
|
|
|
|
for (i = 0; i < ANSICONS_NARGS; i++)
|
|
we->ac_args[i] = 0;
|
|
|
|
(*we->ac_ef->wef_cursor)(we->ac_efa, 1, we->ac_crow, we->ac_ccol);
|
|
}
|
|
|
|
static inline int
|
|
wscons_emul_input_normal(we, c)
|
|
struct wscons_emul_data *we;
|
|
char c;
|
|
{
|
|
int newstate = ANSICONS_STATE_NORMAL;
|
|
int n, scrollskip = we->ac_ef->wef_scrollskip;
|
|
|
|
switch (c) {
|
|
case ASCII_BEL:
|
|
wscons_kbd_bell();
|
|
break;
|
|
|
|
case ASCII_BS:
|
|
if (we->ac_ccol > 0)
|
|
we->ac_ccol--;
|
|
break;
|
|
|
|
case ASCII_HT:
|
|
n = 8 - (we->ac_ccol & 7);
|
|
if (we->ac_ccol + n >= we->ac_ncol)
|
|
n = we->ac_ncol - we->ac_ccol - 1;
|
|
|
|
(*we->ac_ef->wef_erasecols)(we->ac_efa, we->ac_crow,
|
|
we->ac_ccol, we->ac_ccol + n);
|
|
|
|
we->ac_ccol += n;
|
|
break;
|
|
|
|
case ASCII_LF:
|
|
if (we->ac_crow < we->ac_nrow - 1) {
|
|
we->ac_crow++;
|
|
break;
|
|
}
|
|
|
|
#ifdef DIAGNOSTIC
|
|
if (we->ac_crow >= we->ac_nrow)
|
|
panic("wscons_emul: didn't scroll (1)");
|
|
#endif
|
|
|
|
(*we->ac_ef->wef_copyrows)(we->ac_efa, scrollskip, 0,
|
|
we->ac_nrow - scrollskip);
|
|
(*we->ac_ef->wef_eraserows)(we->ac_efa,
|
|
we->ac_nrow - scrollskip, scrollskip);
|
|
we->ac_crow -= scrollskip - 1;
|
|
break;
|
|
|
|
case ASCII_VT:
|
|
if (we->ac_crow > 0)
|
|
we->ac_crow--;
|
|
break;
|
|
|
|
case ASCII_NP:
|
|
(*we->ac_ef->wef_eraserows)(we->ac_efa,
|
|
0, we->ac_nrow - 1);
|
|
|
|
we->ac_ccol = 0;
|
|
we->ac_crow = 0;
|
|
break;
|
|
|
|
case ASCII_CR:
|
|
we->ac_ccol = 0;
|
|
break;
|
|
|
|
case ASCII_ESC:
|
|
if (we->ac_state == ANSICONS_STATE_NORMAL) {
|
|
newstate = ANSICONS_STATE_HAVEESC;
|
|
break;
|
|
}
|
|
/* else fall through; we're printing one out */
|
|
|
|
default:
|
|
(*we->ac_ef->wef_putstr)(we->ac_efa,
|
|
we->ac_crow, we->ac_ccol, &c, 1);
|
|
we->ac_ccol++;
|
|
|
|
/* if the current column is still on the current line, done. */
|
|
if (we->ac_ccol < we->ac_ncol)
|
|
break;
|
|
|
|
/* wrap the column around. */
|
|
we->ac_ccol = 0;
|
|
|
|
/* if the current row isn't the last, increment and leave. */
|
|
if (we->ac_crow < we->ac_nrow - 1) {
|
|
we->ac_crow++;
|
|
break;
|
|
}
|
|
|
|
#ifdef DIAGNOSTIC
|
|
/* check against row overflow */
|
|
if (we->ac_crow >= we->ac_nrow)
|
|
panic("wscons_emul: didn't scroll (2)");
|
|
#endif
|
|
|
|
/* scroll all of the rows up one; leave current row # alone */
|
|
(*we->ac_ef->wef_copyrows)(we->ac_efa, scrollskip, 0,
|
|
we->ac_nrow - scrollskip);
|
|
(*we->ac_ef->wef_eraserows)(we->ac_efa,
|
|
we->ac_nrow - scrollskip, scrollskip);
|
|
we->ac_crow -= scrollskip - 1;
|
|
break;
|
|
}
|
|
|
|
return newstate;
|
|
}
|
|
|
|
static inline int
|
|
wscons_emul_input_haveesc(we, c)
|
|
struct wscons_emul_data *we;
|
|
char c;
|
|
{
|
|
int newstate = ANSICONS_STATE_NORMAL;
|
|
int i;
|
|
|
|
switch (c) {
|
|
case '[':
|
|
for (i = 0; i < ANSICONS_NARGS; i++)
|
|
we->ac_args[i] = 0;
|
|
newstate = ANSICONS_STATE_CONTROL;
|
|
break;
|
|
|
|
default:
|
|
wscons_emul_input_normal(we, ASCII_ESC); /* special cased */
|
|
newstate = wscons_emul_input_normal(we, c);
|
|
break;
|
|
}
|
|
|
|
return newstate;
|
|
}
|
|
|
|
static inline void
|
|
wscons_emul_docontrol(we, c)
|
|
struct wscons_emul_data *we;
|
|
char c;
|
|
{
|
|
int n, m;
|
|
|
|
#if 0
|
|
printf("control: %c: %d, %d\n", c, we->ac_args[0], we->ac_args[1]);
|
|
#endif
|
|
switch (c) {
|
|
case 'A': /* Cursor Up */
|
|
n = we->ac_args[0] ? we->ac_args[0] : 1;
|
|
n = min(n, we->ac_crow);
|
|
we->ac_crow -= n;
|
|
break;
|
|
|
|
case 'B': /* Cursor Down */
|
|
n = we->ac_args[0] ? we->ac_args[0] : 1;
|
|
n = min(n, we->ac_nrow - we->ac_crow - 1);
|
|
we->ac_crow += n;
|
|
break;
|
|
|
|
case 'C': /* Cursor Forward */
|
|
n = we->ac_args[0] ? we->ac_args[0] : 1;
|
|
n = min(n, we->ac_ncol - we->ac_ccol - 1);
|
|
we->ac_ccol += n;
|
|
break;
|
|
|
|
case 'D': /* Cursor Backward */
|
|
n = we->ac_args[0] ? we->ac_args[0] : 1;
|
|
n = min(n, we->ac_ccol);
|
|
we->ac_ccol -= n;
|
|
break;
|
|
|
|
case 'E': /* Cursor Next Line */
|
|
n = we->ac_args[0] ? we->ac_args[0] : 1;
|
|
n = min(n, we->ac_nrow - we->ac_crow - 1);
|
|
we->ac_crow += n;
|
|
we->ac_ccol = 0;
|
|
break;
|
|
|
|
case 'f': /* Horizontal and Vertical Position */
|
|
case 'H': /* Cursor Position */
|
|
m = we->ac_args[1] ? we->ac_args[1] : 1; /* arg 1 */
|
|
m = min(m, we->ac_nrow);
|
|
|
|
n = we->ac_args[0] ? we->ac_args[0] : 1; /* arg 2 */
|
|
n = min(n, we->ac_ncol);
|
|
|
|
we->ac_crow = m - 1;
|
|
we->ac_ccol = n - 1;
|
|
break;
|
|
|
|
case 'J': /* Erase in Display */
|
|
(*we->ac_ef->wef_erasecols)(we->ac_efa, we->ac_crow,
|
|
we->ac_ccol, we->ac_ncol - we->ac_ccol);
|
|
if (we->ac_crow + 1 < we->ac_nrow)
|
|
(*we->ac_ef->wef_eraserows)(we->ac_efa,
|
|
we->ac_crow + 1, we->ac_nrow - we->ac_crow - 1);
|
|
break;
|
|
|
|
case 'K': /* Erase in Line */
|
|
(*we->ac_ef->wef_erasecols)(we->ac_efa, we->ac_crow,
|
|
we->ac_ccol, we->ac_ncol - we->ac_ccol);
|
|
break;
|
|
|
|
case 'L': /* Insert Line */
|
|
{
|
|
int copy_src, copy_dst, copy_nlines;
|
|
|
|
n = we->ac_args[0] ? we->ac_args[0] : 1;
|
|
n = min(n, we->ac_nrow - we->ac_crow);
|
|
|
|
copy_src = we->ac_crow;
|
|
copy_dst = we->ac_crow + n;
|
|
copy_nlines = we->ac_nrow - copy_dst;
|
|
if (copy_nlines > 0)
|
|
(*we->ac_ef->wef_copyrows)(we->ac_efa,
|
|
copy_src, copy_dst, copy_nlines);
|
|
|
|
(*we->ac_ef->wef_eraserows)(we->ac_efa,
|
|
we->ac_crow, n);
|
|
}
|
|
break;
|
|
|
|
case 'M': /* Delete Line */
|
|
{
|
|
int copy_src, copy_dst, copy_nlines;
|
|
|
|
n = we->ac_args[0] ? we->ac_args[0] : 1;
|
|
n = min(n, we->ac_nrow - we->ac_crow);
|
|
|
|
copy_src = we->ac_crow + n;
|
|
copy_dst = we->ac_crow;
|
|
copy_nlines = we->ac_nrow - copy_src;
|
|
if (copy_nlines > 0)
|
|
(*we->ac_ef->wef_copyrows)(we->ac_efa,
|
|
copy_src, copy_dst, copy_nlines);
|
|
|
|
(*we->ac_ef->wef_eraserows)(we->ac_efa,
|
|
we->ac_crow + copy_nlines,
|
|
we->ac_nrow - (we->ac_crow + copy_nlines));
|
|
}
|
|
break;
|
|
|
|
case 'P': /* Delete Character */
|
|
{
|
|
int copy_src, copy_dst, copy_ncols;
|
|
|
|
n = we->ac_args[0] ? we->ac_args[0] : 1;
|
|
n = min(n, we->ac_ncol - we->ac_ccol);
|
|
|
|
copy_src = we->ac_ccol + n;
|
|
copy_dst = we->ac_ccol;
|
|
copy_ncols = we->ac_ncol - copy_src;
|
|
if (copy_ncols > 0)
|
|
(*we->ac_ef->wef_copycols)(we->ac_efa,
|
|
we->ac_crow, copy_src, copy_dst,
|
|
copy_ncols);
|
|
|
|
(*we->ac_ef->wef_erasecols)(we->ac_efa,
|
|
we->ac_crow, we->ac_ccol + copy_ncols,
|
|
we->ac_ncol - (we->ac_ccol + copy_ncols));
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static inline int
|
|
wscons_emul_input_control(we, c)
|
|
struct wscons_emul_data *we;
|
|
char c;
|
|
{
|
|
int newstate = ANSICONS_STATE_CONTROL;
|
|
int i;
|
|
|
|
switch (c) {
|
|
case '0': case '1': case '2': case '3': case '4':
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
we->ac_args[0] *= 10;
|
|
we->ac_args[0] += c - '0';
|
|
break;
|
|
|
|
case ';':
|
|
for (i = 0; i < ANSICONS_NARGS - 1; i++)
|
|
we->ac_args[i + 1] = we->ac_args[i];
|
|
we->ac_args[0] = 0;
|
|
break;
|
|
|
|
default:
|
|
wscons_emul_docontrol(we, c);
|
|
newstate = ANSICONS_STATE_NORMAL;
|
|
break;
|
|
}
|
|
|
|
return newstate;
|
|
}
|
|
|
|
void
|
|
wscons_emul_input(we, cp, n)
|
|
struct wscons_emul_data *we;
|
|
char *cp;
|
|
int n;
|
|
{
|
|
int newstate;
|
|
|
|
(*we->ac_ef->wef_cursor)(we->ac_efa, 0, we->ac_crow, we->ac_ccol);
|
|
for (; n; n--, cp++) {
|
|
switch (we->ac_state) {
|
|
case ANSICONS_STATE_NORMAL:
|
|
newstate = wscons_emul_input_normal(we, *cp);
|
|
break;
|
|
|
|
case ANSICONS_STATE_HAVEESC:
|
|
newstate = wscons_emul_input_haveesc(we, *cp);
|
|
break;
|
|
|
|
case ANSICONS_STATE_CONTROL:
|
|
newstate = wscons_emul_input_control(we, *cp);
|
|
break;
|
|
|
|
default:
|
|
#ifdef DIAGNOSTIC
|
|
panic("wscons_emul: invalid state %d\n", we->ac_state);
|
|
#endif
|
|
/* try to recover, if things get screwed up... */
|
|
newstate = ANSICONS_STATE_NORMAL;
|
|
break;
|
|
}
|
|
|
|
we->ac_state = newstate;
|
|
}
|
|
(*we->ac_ef->wef_cursor)(we->ac_efa, 1, we->ac_crow, we->ac_ccol);
|
|
}
|