summaryrefslogtreecommitdiff
path: root/sys/dev/wscons/wsemul_sun.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/wscons/wsemul_sun.c')
-rw-r--r--sys/dev/wscons/wsemul_sun.c198
1 files changed, 150 insertions, 48 deletions
diff --git a/sys/dev/wscons/wsemul_sun.c b/sys/dev/wscons/wsemul_sun.c
index d490894077b..b698fd3c03f 100644
--- a/sys/dev/wscons/wsemul_sun.c
+++ b/sys/dev/wscons/wsemul_sun.c
@@ -1,7 +1,23 @@
-/* $OpenBSD: wsemul_sun.c,v 1.29 2013/10/18 13:54:09 miod Exp $ */
+/* $OpenBSD: wsemul_sun.c,v 1.30 2013/10/18 22:06:41 miod Exp $ */
/* $NetBSD: wsemul_sun.c,v 1.11 2000/01/05 11:19:36 drochner Exp $ */
/*
+ * Copyright (c) 2007, 2013 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice, this permission notice, and the disclaimer below
+ * appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
* Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -56,7 +72,7 @@ void *wsemul_sun_cnattach(const struct wsscreen_descr *, void *,
void *wsemul_sun_attach(int, const struct wsscreen_descr *,
void *, int, int, void *, long);
u_int wsemul_sun_output(void *, const u_char *, u_int, int);
-int wsemul_sun_translate(void *, keysym_t, const char **);
+int wsemul_sun_translate(void *, kbd_t, keysym_t, const u_char **);
void wsemul_sun_detach(void *, u_int *, u_int *);
void wsemul_sun_resetop(void *, enum wsemul_resetops);
@@ -72,7 +88,10 @@ const struct wsemul_ops wsemul_sun_ops = {
#define SUN_EMUL_STATE_NORMAL 0 /* normal processing */
#define SUN_EMUL_STATE_HAVEESC 1 /* seen start of ctl seq */
-#define SUN_EMUL_STATE_CONTROL 2 /* processing ctl seq */
+#define SUN_EMUL_STATE_CONTROL 2 /* processing ESC [ ctl seq */
+#define SUN_EMUL_STATE_PERCENT 3 /* processing ESC % ctl seq */
+
+#define SUN_EMUL_FLAGS_UTF8 0x01 /* UTF-8 character set */
#define SUN_EMUL_NARGS 2 /* max # of args to a command */
@@ -86,6 +105,7 @@ struct wsemul_sun_emuldata {
long defattr; /* default attribute (rendition) */
u_int state; /* processing state */
+ u_int flags;
u_int args[SUN_EMUL_NARGS]; /* command args, if CONTROL */
int nargs; /* number of args */
@@ -94,6 +114,15 @@ struct wsemul_sun_emuldata {
long kernattr; /* attribute for kernel output */
int attrflags, fgcol, bgcol; /* properties of curattr */
+ struct wsemul_inputstate instate; /* userland input state */
+ struct wsemul_inputstate kstate; /* kernel input state */
+
+#ifdef HAVE_UTF8_SUPPORT
+ u_char translatebuf[6];
+#else
+ u_char translatebuf[1];
+#endif
+
#ifdef DIAGNOSTIC
int console;
#endif
@@ -104,11 +133,18 @@ void wsemul_sun_init(struct wsemul_sun_emuldata *,
int wsemul_sun_jump_scroll(struct wsemul_sun_emuldata *, const u_char *,
u_int, int);
void wsemul_sun_reset(struct wsemul_sun_emuldata *);
-int wsemul_sun_output_lowchars(struct wsemul_sun_emuldata *, u_char, int);
-int wsemul_sun_output_normal(struct wsemul_sun_emuldata *, u_char, int);
-void wsemul_sun_output_haveesc(struct wsemul_sun_emuldata *, u_char);
-int wsemul_sun_output_control(struct wsemul_sun_emuldata *, u_char);
-int wsemul_sun_control(struct wsemul_sun_emuldata *, u_char);
+int wsemul_sun_output_lowchars(struct wsemul_sun_emuldata *,
+ struct wsemul_inputstate *, int);
+int wsemul_sun_output_normal(struct wsemul_sun_emuldata *,
+ struct wsemul_inputstate *, int);
+int wsemul_sun_output_haveesc(struct wsemul_sun_emuldata *,
+ struct wsemul_inputstate *);
+int wsemul_sun_output_control(struct wsemul_sun_emuldata *,
+ struct wsemul_inputstate *);
+int wsemul_sun_output_percent(struct wsemul_sun_emuldata *,
+ struct wsemul_inputstate *);
+int wsemul_sun_control(struct wsemul_sun_emuldata *,
+ struct wsemul_inputstate *);
int wsemul_sun_selectattribute(struct wsemul_sun_emuldata *, int, int, int,
long *, long *);
int wsemul_sun_scrollup(struct wsemul_sun_emuldata *, u_int);
@@ -141,12 +177,17 @@ wsemul_sun_init(struct wsemul_sun_emuldata *edp,
void
wsemul_sun_reset(struct wsemul_sun_emuldata *edp)
{
+ edp->flags = 0;
edp->state = SUN_EMUL_STATE_NORMAL;
edp->bkgdattr = edp->curattr = edp->defattr;
edp->attrflags = 0;
edp->fgcol = WSCOL_BLACK;
edp->bgcol = WSCOL_WHITE;
edp->scrolldist = 1;
+ edp->instate.inchar = 0;
+ edp->instate.mbleft = 0;
+ edp->kstate.inchar = 0;
+ edp->kstate.mbleft = 0;
}
void *
@@ -222,13 +263,13 @@ wsemul_sun_attach(int console, const struct wsscreen_descr *type, void *cookie,
}
int
-wsemul_sun_output_lowchars(struct wsemul_sun_emuldata *edp, u_char c,
- int kernel)
+wsemul_sun_output_lowchars(struct wsemul_sun_emuldata *edp,
+ struct wsemul_inputstate *instate, int kernel)
{
u_int n;
int rc = 0;
- switch (c) {
+ switch (instate->inchar) {
case ASCII_NUL:
default:
/* ignore */
@@ -298,13 +339,16 @@ wsemul_sun_output_lowchars(struct wsemul_sun_emuldata *edp, u_char c,
}
int
-wsemul_sun_output_normal(struct wsemul_sun_emuldata *edp, u_char c, int kernel)
+wsemul_sun_output_normal(struct wsemul_sun_emuldata *edp,
+ struct wsemul_inputstate *instate, int kernel)
{
int rc;
+ u_int outchar;
+ (*edp->emulops->mapchar)(edp->emulcookie, instate->inchar, &outchar);
WSEMULOP(rc, edp, &edp->abortstate, putchar,
(edp->emulcookie, edp->crow, edp->ccol,
- c, kernel ? edp->kernattr : edp->curattr));
+ outchar, kernel ? edp->kernattr : edp->curattr));
if (rc != 0)
return rc;
@@ -327,34 +371,41 @@ wsemul_sun_output_normal(struct wsemul_sun_emuldata *edp, u_char c, int kernel)
return 0;
}
-void
-wsemul_sun_output_haveesc(struct wsemul_sun_emuldata *edp, u_char c)
+int
+wsemul_sun_output_haveesc(struct wsemul_sun_emuldata *edp,
+ struct wsemul_inputstate *instate)
{
- switch (c) {
+ switch (instate->inchar) {
case '[': /* continuation of multi-char sequence */
edp->nargs = 0;
bzero(edp->args, sizeof (edp->args));
edp->state = SUN_EMUL_STATE_CONTROL;
break;
-
+#ifdef HAVE_UTF8_SUPPORT
+ case '%':
+ edp->state = SUN_EMUL_STATE_PERCENT;
+ break;
+#endif
default:
#ifdef DEBUG
- printf("ESC%c unknown\n", c);
+ printf("ESC %x unknown\n", instate->inchar);
#endif
edp->state = SUN_EMUL_STATE_NORMAL; /* XXX is this wise? */
break;
}
+ return 0;
}
int
-wsemul_sun_control(struct wsemul_sun_emuldata *edp, u_char c)
+wsemul_sun_control(struct wsemul_sun_emuldata *edp,
+ struct wsemul_inputstate *instate)
{
u_int n, src, dst;
int flags, fgcol, bgcol;
long attr, bkgdattr;
int rc = 0;
- switch (c) {
+ switch (instate->inchar) {
case '@': /* "Insert Character (ICH)" */
n = min(NORMALIZE(ARG(0,1)), COLS_LEFT + 1);
src = edp->ccol;
@@ -541,12 +592,13 @@ setattr:
}
int
-wsemul_sun_output_control(struct wsemul_sun_emuldata *edp, u_char c)
+wsemul_sun_output_control(struct wsemul_sun_emuldata *edp,
+ struct wsemul_inputstate *instate)
{
int oargs;
int rc;
- switch (c) {
+ switch (instate->inchar) {
case '0': case '1': case '2': case '3': case '4': /* argument digit */
case '5': case '6': case '7': case '8': case '9':
/*
@@ -559,7 +611,7 @@ wsemul_sun_output_control(struct wsemul_sun_emuldata *edp, u_char c)
edp->args[edp->nargs = SUN_EMUL_NARGS - 1] = 0;
}
edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) +
- (c - '0');
+ (instate->inchar - '0');
break;
case ';': /* argument terminator */
@@ -570,7 +622,7 @@ wsemul_sun_output_control(struct wsemul_sun_emuldata *edp, u_char c)
oargs = edp->nargs++;
if (edp->nargs > SUN_EMUL_NARGS)
edp->nargs = SUN_EMUL_NARGS;
- rc = wsemul_sun_control(edp, c);
+ rc = wsemul_sun_control(edp, instate);
if (rc != 0) {
/* undo nargs progress */
edp->nargs = oargs;
@@ -584,12 +636,31 @@ wsemul_sun_output_control(struct wsemul_sun_emuldata *edp, u_char c)
return 0;
}
+#ifdef HAVE_UTF8_SUPPORT
+int
+wsemul_sun_output_percent(struct wsemul_sun_emuldata *edp,
+ struct wsemul_inputstate *instate)
+{
+ switch (instate->inchar) {
+ case 'G':
+ edp->flags |= SUN_EMUL_FLAGS_UTF8;
+ edp->kstate.mbleft = edp->instate.mbleft = 0;
+ break;
+ case '@':
+ edp->flags &= ~SUN_EMUL_FLAGS_UTF8;
+ break;
+ }
+ edp->state = SUN_EMUL_STATE_NORMAL;
+ return 0;
+}
+#endif
+
u_int
wsemul_sun_output(void *cookie, const u_char *data, u_int count, int kernel)
{
struct wsemul_sun_emuldata *edp = cookie;
+ struct wsemul_inputstate *instate;
u_int processed = 0;
- u_char c;
#ifdef HAVE_JUMP_SCROLL
int lines;
#endif
@@ -600,6 +671,8 @@ wsemul_sun_output(void *cookie, const u_char *data, u_int count, int kernel)
panic("wsemul_sun_output: kernel output, not console");
#endif
+ instate = kernel ? &edp->kstate : &edp->instate;
+
switch (edp->abortstate.state) {
case ABORT_FAILED_CURSOR:
/*
@@ -622,7 +695,7 @@ wsemul_sun_output(void *cookie, const u_char *data, u_int count, int kernel)
break;
}
- for (; count > 0; data++, count--) {
+ for (;;) {
#ifdef HAVE_JUMP_SCROLL
switch (edp->abortstate.state) {
case ABORT_FAILED_JUMP_SCROLL:
@@ -671,9 +744,18 @@ wsemul_sun_output(void *cookie, const u_char *data, u_int count, int kernel)
wsemul_resume_abort(&edp->abortstate);
- c = *data;
- if (c < ' ') {
- rc = wsemul_sun_output_lowchars(edp, c, kernel);
+ if (wsemul_getchar(&data, &count, instate,
+#ifdef HAVE_UTF8_SUPPORT
+ (edp->state == SUN_EMUL_STATE_NORMAL && !kernel) ?
+ edp->flags & SUN_EMUL_FLAGS_UTF8 : 0
+#else
+ 0
+#endif
+ ) != 0)
+ break;
+
+ if (instate->inchar < ' ') {
+ rc = wsemul_sun_output_lowchars(edp, instate, kernel);
if (rc != 0)
break;
processed++;
@@ -681,7 +763,7 @@ wsemul_sun_output(void *cookie, const u_char *data, u_int count, int kernel)
}
if (kernel) {
- rc = wsemul_sun_output_normal(edp, c, 1);
+ rc = wsemul_sun_output_normal(edp, instate, 1);
if (rc != 0)
break;
processed++;
@@ -690,21 +772,26 @@ wsemul_sun_output(void *cookie, const u_char *data, u_int count, int kernel)
switch (edp->state) {
case SUN_EMUL_STATE_NORMAL:
- rc = wsemul_sun_output_normal(edp, c, 0);
+ rc = wsemul_sun_output_normal(edp, instate, 0);
break;
case SUN_EMUL_STATE_HAVEESC:
- wsemul_sun_output_haveesc(edp, c);
+ rc = wsemul_sun_output_haveesc(edp, instate);
break;
case SUN_EMUL_STATE_CONTROL:
- rc = wsemul_sun_output_control(edp, c);
+ rc = wsemul_sun_output_control(edp, instate);
+ break;
+#ifdef HAVE_UTF8_SUPPORT
+ case SUN_EMUL_STATE_PERCENT:
+ rc = wsemul_sun_output_percent(edp, instate);
break;
+#endif
default:
#ifdef DIAGNOSTIC
panic("wsemul_sun: invalid state %d", edp->state);
#else
/* try to recover, if things get screwed up... */
edp->state = SUN_EMUL_STATE_NORMAL;
- rc = wsemul_sun_output_normal(edp, c, 0);
+ rc = wsemul_sun_output_normal(edp, instate, 0);
#endif
break;
}
@@ -740,18 +827,26 @@ int
wsemul_sun_jump_scroll(struct wsemul_sun_emuldata *edp, const u_char *data,
u_int count, int kernel)
{
- u_char curchar;
u_int pos, lines;
+ struct wsemul_inputstate tmpstate;
lines = 0;
pos = edp->ccol;
- for (; count != 0; data++, count--) {
- curchar = *data;
- if (curchar == ASCII_FF ||
- curchar == ASCII_VT || curchar == ASCII_ESC)
+ tmpstate = kernel ? edp->kstate : edp->instate; /* structure copy */
+
+ while (wsemul_getchar(&data, &count, &tmpstate,
+#ifdef HAVE_UTF8_SUPPORT
+ kernel ? 0 : edp->flags & SUN_EMUL_FLAGS_UTF8
+#else
+ 0
+#endif
+ ) == 0) {
+ if (tmpstate.inchar == ASCII_FF ||
+ tmpstate.inchar == ASCII_VT ||
+ tmpstate.inchar == ASCII_ESC)
break;
- switch (curchar) {
+ switch (tmpstate.inchar) {
case ASCII_BS:
if (pos > 0)
pos--;
@@ -769,11 +864,11 @@ wsemul_sun_jump_scroll(struct wsemul_sun_emuldata *edp, const u_char *data,
default:
if (++pos >= edp->ncols) {
pos = 0;
- curchar = ASCII_LF;
+ tmpstate.inchar = ASCII_LF;
}
break;
}
- if (curchar == ASCII_LF) {
+ if (tmpstate.inchar == ASCII_LF) {
if (++lines >= edp->nrows - 1)
break;
}
@@ -849,7 +944,7 @@ wsemul_sun_selectattribute(struct wsemul_sun_emuldata *edp, int flags,
return (0);
}
-static const char *sun_fkeys[] = {
+static const u_char *sun_fkeys[] = {
"\033[224z", /* F1 */
"\033[225z",
"\033[226z",
@@ -864,7 +959,7 @@ static const char *sun_fkeys[] = {
"\033[235z", /* F12 */
};
-static const char *sun_lkeys[] = {
+static const u_char *sun_lkeys[] = {
"\033[207z", /* KS_Help */
NULL, /* KS_Execute */
"\033[200z", /* KS_Find */
@@ -880,13 +975,20 @@ static const char *sun_lkeys[] = {
};
int
-wsemul_sun_translate(void *cookie, keysym_t in, const char **out)
+wsemul_sun_translate(void *cookie, kbd_t layout, keysym_t in,
+ const u_char **out)
{
- static char c;
+ struct wsemul_sun_emuldata *edp = cookie;
+
+ if (KS_GROUP(in) == KS_GROUP_Ascii) {
+ *out = edp->translatebuf;
+ return (wsemul_utf8_translate(KS_VALUE(in), layout,
+ edp->translatebuf, edp->flags & SUN_EMUL_FLAGS_UTF8));
+ }
if (KS_GROUP(in) == KS_GROUP_Keypad && (in & 0x80) == 0) {
- c = in & 0xff; /* turn into ASCII */
- *out = &c;
+ edp->translatebuf[0] = in & 0xff; /* turn into ASCII */
+ *out = edp->translatebuf;
return (1);
}