scterm-teken.c revision 262861
1250199Sgrehan/*- 2298446Ssephe * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 3250199Sgrehan * All rights reserved. 4250199Sgrehan * 5250199Sgrehan * Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org> 6250199Sgrehan * All rights reserved. 7250199Sgrehan * 8250199Sgrehan * Redistribution and use in source and binary forms, with or without 9250199Sgrehan * modification, are permitted provided that the following conditions 10250199Sgrehan * are met: 11250199Sgrehan * 1. Redistributions of source code must retain the above copyright 12250199Sgrehan * notice, this list of conditions and the following disclaimer as 13250199Sgrehan * the first lines of this file unmodified. 14250199Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 15250199Sgrehan * notice, this list of conditions and the following disclaimer in the 16250199Sgrehan * documentation and/or other materials provided with the distribution. 17250199Sgrehan * 18250199Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 19250199Sgrehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20250199Sgrehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21250199Sgrehan * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22250199Sgrehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23250199Sgrehan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24250199Sgrehan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25250199Sgrehan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26250199Sgrehan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27250199Sgrehan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28250199Sgrehan */ 29256276Sdim 30256276Sdim#include <sys/cdefs.h> 31256276Sdim__FBSDID("$FreeBSD: stable/10/sys/dev/syscons/scterm-teken.c 262861 2014-03-06 18:30:56Z jhb $"); 32250199Sgrehan 33296028Ssephe#include "opt_syscons.h" 34250199Sgrehan#include "opt_teken.h" 35250199Sgrehan 36250199Sgrehan#include <sys/param.h> 37250199Sgrehan#include <sys/systm.h> 38250199Sgrehan#include <sys/kernel.h> 39296181Ssephe#include <sys/module.h> 40301588Ssephe#include <sys/consio.h> 41301588Ssephe#include <sys/kbio.h> 42250199Sgrehan 43301588Ssephe#if defined(__arm__) || defined(__mips__) || \ 44250199Sgrehan defined(__powerpc__) || defined(__sparc64__) 45250199Sgrehan#include <machine/sc_machdep.h> 46250199Sgrehan#else 47250199Sgrehan#include <machine/pc/display.h> 48300102Ssephe#endif 49301588Ssephe 50300102Ssephe#include <dev/syscons/syscons.h> 51250199Sgrehan 52250199Sgrehan#include <teken/teken.h> 53294886Ssephe 54250199Sgrehanstatic void scteken_revattr(unsigned char, teken_attr_t *); 55250199Sgrehanstatic unsigned int scteken_attr(const teken_attr_t *); 56250199Sgrehan 57250199Sgrehanstatic sc_term_init_t scteken_init; 58250199Sgrehanstatic sc_term_term_t scteken_term; 59250199Sgrehanstatic sc_term_puts_t scteken_puts; 60250199Sgrehanstatic sc_term_ioctl_t scteken_ioctl; 61301583Ssephestatic sc_term_default_attr_t scteken_default_attr; 62302557Ssephestatic sc_term_clear_t scteken_clear; 63301583Ssephestatic sc_term_input_t scteken_input; 64301588Ssephestatic sc_term_fkeystr_t scteken_fkeystr; 65250199Sgrehanstatic void scteken_nop(void); 66301588Ssephe 67301588Ssephetypedef struct { 68301588Ssephe teken_t ts_teken; 69250199Sgrehan int ts_busy; 70301583Ssephe} teken_stat; 71250199Sgrehan 72250199Sgrehanstatic teken_stat reserved_teken_stat; 73256276Sdim 74250199Sgrehanstatic sc_term_sw_t sc_term_scteken = { 75282212Swhu { NULL, NULL }, 76250199Sgrehan "scteken", /* emulator name */ 77250199Sgrehan "teken terminal", /* description */ 78250199Sgrehan "*", /* matching renderer */ 79250199Sgrehan sizeof(teken_stat), /* softc size */ 80296289Ssephe 0, 81296289Ssephe scteken_init, 82296289Ssephe scteken_term, 83296289Ssephe scteken_puts, 84296289Ssephe scteken_ioctl, 85296289Ssephe (sc_term_reset_t *)scteken_nop, 86296289Ssephe scteken_default_attr, 87296289Ssephe scteken_clear, 88296289Ssephe (sc_term_notify_t *)scteken_nop, 89296289Ssephe scteken_input, 90296289Ssephe scteken_fkeystr, 91296181Ssephe}; 92296290Ssephe 93296181SsepheSCTERM_MODULE(scteken, sc_term_scteken); 94296181Ssephe 95296181Ssephestatic tf_bell_t scteken_bell; 96296181Ssephestatic tf_cursor_t scteken_cursor; 97296181Ssephestatic tf_putchar_t scteken_putchar; 98296181Ssephestatic tf_fill_t scteken_fill; 99296181Ssephestatic tf_copy_t scteken_copy; 100296181Ssephestatic tf_param_t scteken_param; 101296181Ssephestatic tf_respond_t scteken_respond; 102296181Ssephe 103296181Ssephestatic const teken_funcs_t scteken_funcs = { 104296181Ssephe .tf_bell = scteken_bell, 105296181Ssephe .tf_cursor = scteken_cursor, 106296181Ssephe .tf_putchar = scteken_putchar, 107296181Ssephe .tf_fill = scteken_fill, 108296181Ssephe .tf_copy = scteken_copy, 109296181Ssephe .tf_param = scteken_param, 110296181Ssephe .tf_respond = scteken_respond, 111296181Ssephe}; 112296181Ssephe 113296181Ssephestatic int 114296181Ssephescteken_init(scr_stat *scp, void **softc, int code) 115296181Ssephe{ 116296181Ssephe teken_stat *ts; 117298693Ssephe teken_pos_t tp; 118296181Ssephe 119296181Ssephe if (*softc == NULL) { 120296181Ssephe if (reserved_teken_stat.ts_busy) 121296181Ssephe return (EINVAL); 122298693Ssephe *softc = &reserved_teken_stat; 123296181Ssephe } 124296181Ssephe ts = *softc; 125296181Ssephe 126296181Ssephe switch (code) { 127298693Ssephe case SC_TE_COLD_INIT: 128296181Ssephe ++sc_term_scteken.te_refcount; 129296181Ssephe ts->ts_busy = 1; 130296181Ssephe /* FALLTHROUGH */ 131298693Ssephe case SC_TE_WARM_INIT: 132296188Ssephe teken_init(&ts->ts_teken, &scteken_funcs, scp); 133296188Ssephe#ifndef TEKEN_UTF8 134296188Ssephe teken_set_8bit(&ts->ts_teken); 135296188Ssephe#endif /* !TEKEN_UTF8 */ 136296181Ssephe#ifdef TEKEN_CONS25 137296188Ssephe teken_set_cons25(&ts->ts_teken); 138296188Ssephe#endif /* TEKEN_CONS25 */ 139296289Ssephe 140298693Ssephe tp.tp_row = scp->ysize; 141298693Ssephe tp.tp_col = scp->xsize; 142296289Ssephe teken_set_winsize(&ts->ts_teken, &tp); 143296188Ssephe 144296181Ssephe if (scp->cursor_pos < scp->ysize * scp->xsize) { 145296181Ssephe /* Valid old cursor position. */ 146296181Ssephe tp.tp_row = scp->cursor_pos / scp->xsize; 147296181Ssephe tp.tp_col = scp->cursor_pos % scp->xsize; 148298693Ssephe teken_set_cursor(&ts->ts_teken, &tp); 149296181Ssephe } 150296181Ssephe break; 151296181Ssephe } 152296181Ssephe 153298693Ssephe return (0); 154296181Ssephe} 155296181Ssephe 156296181Ssephestatic int 157296181Ssephescteken_term(scr_stat *scp, void **softc) 158296181Ssephe{ 159296181Ssephe 160296181Ssephe if (*softc == &reserved_teken_stat) { 161296181Ssephe *softc = NULL; 162296181Ssephe reserved_teken_stat.ts_busy = 0; 163296290Ssephe } 164250199Sgrehan --sc_term_scteken.te_refcount; 165250199Sgrehan 166250199Sgrehan return (0); 167250199Sgrehan} 168250199Sgrehan 169250199Sgrehanstatic void 170250199Sgrehanscteken_puts(scr_stat *scp, u_char *buf, int len, int kernel) 171250199Sgrehan{ 172250199Sgrehan teken_stat *ts = scp->ts; 173250199Sgrehan teken_attr_t backup, kattr; 174250199Sgrehan 175250199Sgrehan scp->sc->write_in_progress++; 176250199Sgrehan if (kernel) { 177302607Ssephe /* Use special colors for kernel messages. */ 178302607Ssephe backup = *teken_get_curattr(&ts->ts_teken); 179302607Ssephe scteken_revattr(SC_KERNEL_CONS_ATTR, &kattr); 180302607Ssephe teken_set_curattr(&ts->ts_teken, &kattr); 181302607Ssephe teken_input(&ts->ts_teken, buf, len); 182302607Ssephe teken_set_curattr(&ts->ts_teken, &backup); 183250199Sgrehan } else { 184250199Sgrehan /* Print user messages with regular colors. */ 185250199Sgrehan teken_input(&ts->ts_teken, buf, len); 186302607Ssephe } 187302607Ssephe scp->sc->write_in_progress--; 188302607Ssephe} 189302607Ssephe 190302607Ssephestatic int 191302607Ssephescteken_ioctl(scr_stat *scp, struct tty *tp, u_long cmd, caddr_t data, 192302607Ssephe struct thread *td) 193282212Swhu{ 194282212Swhu teken_stat *ts = scp->ts; 195282212Swhu vid_info_t *vi; 196282212Swhu unsigned int attr; 197282212Swhu 198282212Swhu switch (cmd) { 199282212Swhu case GIO_ATTR: /* get current attributes */ 200282212Swhu *(int*)data = 201282212Swhu scteken_attr(teken_get_curattr(&ts->ts_teken)); 202282212Swhu return (0); 203282212Swhu case CONS_GETINFO: /* get current (virtual) console info */ 204282212Swhu vi = (vid_info_t *)data; 205250199Sgrehan if (vi->size != sizeof(struct vid_info)) 206250199Sgrehan return EINVAL; 207250199Sgrehan 208300102Ssephe attr = scteken_attr(teken_get_defattr(&ts->ts_teken)); 209300102Ssephe vi->mv_norm.fore = attr & 0x0f; 210302557Ssephe vi->mv_norm.back = (attr >> 4) & 0x0f; 211300646Ssephe vi->mv_rev.fore = vi->mv_norm.back; 212294886Ssephe vi->mv_rev.back = vi->mv_norm.fore; 213294886Ssephe /* 214250199Sgrehan * The other fields are filled by the upper routine. XXX 215250199Sgrehan */ 216256350Sgrehan return (ENOIOCTL); 217250199Sgrehan } 218250199Sgrehan 219250199Sgrehan return (ENOIOCTL); 220256350Sgrehan} 221250199Sgrehan 222250199Sgrehanstatic void 223250199Sgrehanscteken_default_attr(scr_stat *scp, int color, int rev_color) 224250199Sgrehan{ 225256350Sgrehan teken_stat *ts = scp->ts; 226256350Sgrehan teken_attr_t ta; 227256350Sgrehan 228256350Sgrehan scteken_revattr(color, &ta); 229250199Sgrehan teken_set_defattr(&ts->ts_teken, &ta); 230250199Sgrehan} 231250199Sgrehan 232250199Sgrehanstatic void 233250199Sgrehanscteken_clear(scr_stat *scp) 234250199Sgrehan{ 235250199Sgrehan 236250199Sgrehan sc_move_cursor(scp, 0, 0); 237250199Sgrehan sc_vtb_clear(&scp->vtb, scp->sc->scr_map[0x20], SC_NORM_ATTR << 8); 238250199Sgrehan mark_all(scp); 239250199Sgrehan} 240296290Ssephe 241296290Ssephestatic int 242296181Ssephescteken_input(scr_stat *scp, int c, struct tty *tp) 243250199Sgrehan{ 244250199Sgrehan 245250199Sgrehan return FALSE; 246250199Sgrehan} 247250199Sgrehan 248250199Sgrehanstatic const char * 249250199Sgrehanscteken_fkeystr(scr_stat *scp, int c) 250250199Sgrehan{ 251250199Sgrehan teken_stat *ts = scp->ts; 252250199Sgrehan unsigned int k; 253302607Ssephe 254302607Ssephe switch (c) { 255250199Sgrehan case FKEY | F(1): case FKEY | F(2): case FKEY | F(3): 256302607Ssephe case FKEY | F(4): case FKEY | F(5): case FKEY | F(6): 257302607Ssephe case FKEY | F(7): case FKEY | F(8): case FKEY | F(9): 258302607Ssephe case FKEY | F(10): case FKEY | F(11): case FKEY | F(12): 259302607Ssephe k = TKEY_F1 + c - (FKEY | F(1)); 260302607Ssephe break; 261302607Ssephe case FKEY | F(49): 262302607Ssephe k = TKEY_HOME; 263250199Sgrehan break; 264302607Ssephe case FKEY | F(50): 265302607Ssephe k = TKEY_UP; 266302607Ssephe break; 267302607Ssephe case FKEY | F(51): 268302607Ssephe k = TKEY_PAGE_UP; 269302607Ssephe break; 270302607Ssephe case FKEY | F(53): 271250199Sgrehan k = TKEY_LEFT; 272302607Ssephe break; 273250199Sgrehan case FKEY | F(55): 274302607Ssephe k = TKEY_RIGHT; 275302607Ssephe break; 276302607Ssephe case FKEY | F(57): 277302607Ssephe k = TKEY_END; 278302607Ssephe break; 279302607Ssephe case FKEY | F(58): 280302607Ssephe k = TKEY_DOWN; 281302607Ssephe break; 282250199Sgrehan case FKEY | F(59): 283302607Ssephe k = TKEY_PAGE_DOWN; 284302607Ssephe break; 285302607Ssephe case FKEY | F(60): 286250199Sgrehan k = TKEY_INSERT; 287302607Ssephe break; 288250199Sgrehan case FKEY | F(61): 289302607Ssephe k = TKEY_DELETE; 290302607Ssephe break; 291302607Ssephe default: 292302607Ssephe return (NULL); 293302607Ssephe } 294302607Ssephe 295250199Sgrehan return (teken_get_sequence(&ts->ts_teken, k)); 296302607Ssephe} 297302607Ssephe 298302607Ssephestatic void 299250199Sgrehanscteken_nop(void) 300250199Sgrehan{ 301250199Sgrehan 302250199Sgrehan} 303250199Sgrehan 304302609Ssephe/* 305250199Sgrehan * libteken routines. 306302609Ssephe */ 307302609Ssephe 308302609Ssephestatic const unsigned char fgcolors_normal[TC_NCOLORS] = { 309250199Sgrehan FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, 310302609Ssephe FG_BLUE, FG_MAGENTA, FG_CYAN, FG_LIGHTGREY, 311302609Ssephe}; 312302609Ssephe 313302609Ssephestatic const unsigned char fgcolors_bold[TC_NCOLORS] = { 314302609Ssephe FG_DARKGREY, FG_LIGHTRED, FG_LIGHTGREEN, FG_YELLOW, 315302609Ssephe FG_LIGHTBLUE, FG_LIGHTMAGENTA, FG_LIGHTCYAN, FG_WHITE, 316302609Ssephe}; 317302609Ssephe 318250199Sgrehanstatic const unsigned char bgcolors[TC_NCOLORS] = { 319302609Ssephe BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, 320302609Ssephe BG_BLUE, BG_MAGENTA, BG_CYAN, BG_LIGHTGREY, 321302609Ssephe}; 322250199Sgrehan 323302609Ssephestatic void 324302609Ssephescteken_revattr(unsigned char color, teken_attr_t *a) 325250199Sgrehan{ 326250199Sgrehan teken_color_t fg, bg; 327302609Ssephe 328302609Ssephe /* 329302609Ssephe * XXX: Reverse conversion of syscons to teken attributes. Not 330302609Ssephe * realiable. Maybe we should turn it into a 1:1 mapping one of 331250199Sgrehan * these days? 332302609Ssephe */ 333302609Ssephe 334302609Ssephe a->ta_format = 0; 335302609Ssephe a->ta_fgcolor = TC_WHITE; 336302609Ssephe a->ta_bgcolor = TC_BLACK; 337302609Ssephe 338302609Ssephe#ifdef FG_BLINK 339302609Ssephe if (color & FG_BLINK) { 340250199Sgrehan a->ta_format |= TF_BLINK; 341250199Sgrehan color &= ~FG_BLINK; 342302609Ssephe } 343302609Ssephe#endif /* FG_BLINK */ 344302609Ssephe 345302609Ssephe for (fg = 0; fg < TC_NCOLORS; fg++) { 346296076Ssephe for (bg = 0; bg < TC_NCOLORS; bg++) { 347302609Ssephe if ((fgcolors_normal[fg] | bgcolors[bg]) == color) { 348250199Sgrehan a->ta_fgcolor = fg; 349302609Ssephe a->ta_bgcolor = bg; 350302609Ssephe return; 351302609Ssephe } 352302609Ssephe 353302609Ssephe if ((fgcolors_bold[fg] | bgcolors[bg]) == color) { 354302609Ssephe a->ta_fgcolor = fg; 355302609Ssephe a->ta_bgcolor = bg; 356302609Ssephe a->ta_format |= TF_BOLD; 357302609Ssephe return; 358302609Ssephe } 359302609Ssephe } 360302609Ssephe } 361302609Ssephe} 362250199Sgrehan 363302609Ssephestatic unsigned int 364302609Ssephescteken_attr(const teken_attr_t *a) 365302609Ssephe{ 366302609Ssephe unsigned int attr = 0; 367302609Ssephe teken_color_t fg, bg; 368302609Ssephe 369302609Ssephe if (a->ta_format & TF_REVERSE) { 370302609Ssephe fg = teken_256to8(a->ta_bgcolor); 371250199Sgrehan bg = teken_256to8(a->ta_fgcolor); 372250199Sgrehan } else { 373302609Ssephe fg = teken_256to8(a->ta_fgcolor); 374302609Ssephe bg = teken_256to8(a->ta_bgcolor); 375302609Ssephe } 376302609Ssephe if (a->ta_format & TF_BOLD) 377302609Ssephe attr |= fgcolors_bold[fg]; 378302609Ssephe else 379302609Ssephe attr |= fgcolors_normal[fg]; 380302609Ssephe attr |= bgcolors[bg]; 381302609Ssephe 382302609Ssephe#ifdef FG_UNDERLINE 383250199Sgrehan if (a->ta_format & TF_UNDERLINE) 384302609Ssephe attr |= FG_UNDERLINE; 385302609Ssephe#endif /* FG_UNDERLINE */ 386302609Ssephe#ifdef FG_BLINK 387302609Ssephe if (a->ta_format & TF_BLINK) 388302609Ssephe attr |= FG_BLINK; 389302609Ssephe#endif /* FG_BLINK */ 390302609Ssephe 391302609Ssephe return (attr); 392250199Sgrehan} 393302609Ssephe 394302609Ssephestatic void 395250199Sgrehanscteken_bell(void *arg) 396302609Ssephe{ 397302609Ssephe scr_stat *scp = arg; 398302609Ssephe 399302609Ssephe sc_bell(scp, scp->bell_pitch, scp->bell_duration); 400302609Ssephe} 401250199Sgrehan 402302609Ssephestatic void 403302609Ssephescteken_cursor(void *arg, const teken_pos_t *p) 404302609Ssephe{ 405250199Sgrehan scr_stat *scp = arg; 406302609Ssephe 407302609Ssephe sc_move_cursor(scp, p->tp_col, p->tp_row); 408302609Ssephe} 409302609Ssephe 410302609Ssephe#ifdef TEKEN_UTF8 411250199Sgrehanstruct unicp437 { 412302609Ssephe uint16_t unicode_base; 413250199Sgrehan uint8_t cp437_base; 414302609Ssephe uint8_t length; 415250199Sgrehan}; 416302609Ssephe 417302609Ssephestatic const struct unicp437 cp437table[] = { 418302609Ssephe { 0x0020, 0x20, 0x5e }, { 0x00a0, 0x20, 0x00 }, 419250199Sgrehan { 0x00a1, 0xad, 0x00 }, { 0x00a2, 0x9b, 0x00 }, 420302609Ssephe { 0x00a3, 0x9c, 0x00 }, { 0x00a5, 0x9d, 0x00 }, 421250199Sgrehan { 0x00a7, 0x15, 0x00 }, { 0x00aa, 0xa6, 0x00 }, 422302609Ssephe { 0x00ab, 0xae, 0x00 }, { 0x00ac, 0xaa, 0x00 }, 423302609Ssephe { 0x00b0, 0xf8, 0x00 }, { 0x00b1, 0xf1, 0x00 }, 424302609Ssephe { 0x00b2, 0xfd, 0x00 }, { 0x00b5, 0xe6, 0x00 }, 425302609Ssephe { 0x00b6, 0x14, 0x00 }, { 0x00b7, 0xfa, 0x00 }, 426302609Ssephe { 0x00ba, 0xa7, 0x00 }, { 0x00bb, 0xaf, 0x00 }, 427302609Ssephe { 0x00bc, 0xac, 0x00 }, { 0x00bd, 0xab, 0x00 }, 428250199Sgrehan { 0x00bf, 0xa8, 0x00 }, { 0x00c0, 0x41, 0x00 }, 429250199Sgrehan { 0x00c1, 0x41, 0x00 }, { 0x00c2, 0x41, 0x00 }, 430250199Sgrehan { 0x00c4, 0x8e, 0x01 }, { 0x00c6, 0x92, 0x00 }, 431250199Sgrehan { 0x00c7, 0x80, 0x00 }, { 0x00c8, 0x45, 0x00 }, 432250199Sgrehan { 0x00c9, 0x90, 0x00 }, { 0x00ca, 0x45, 0x00 }, 433250199Sgrehan { 0x00cb, 0x45, 0x00 }, { 0x00cc, 0x49, 0x00 }, 434250199Sgrehan { 0x00cd, 0x49, 0x00 }, { 0x00ce, 0x49, 0x00 }, 435250199Sgrehan { 0x00cf, 0x49, 0x00 }, { 0x00d1, 0xa5, 0x00 }, 436250199Sgrehan { 0x00d2, 0x4f, 0x00 }, { 0x00d3, 0x4f, 0x00 }, 437250199Sgrehan { 0x00d4, 0x4f, 0x00 }, { 0x00d6, 0x99, 0x00 }, 438250199Sgrehan { 0x00d9, 0x55, 0x00 }, { 0x00da, 0x55, 0x00 }, 439250199Sgrehan { 0x00db, 0x55, 0x00 }, { 0x00dc, 0x9a, 0x00 }, 440250199Sgrehan { 0x00df, 0xe1, 0x00 }, { 0x00e0, 0x85, 0x00 }, 441250199Sgrehan { 0x00e1, 0xa0, 0x00 }, { 0x00e2, 0x83, 0x00 }, 442250199Sgrehan { 0x00e4, 0x84, 0x00 }, { 0x00e5, 0x86, 0x00 }, 443250199Sgrehan { 0x00e6, 0x91, 0x00 }, { 0x00e7, 0x87, 0x00 }, 444250199Sgrehan { 0x00e8, 0x8a, 0x00 }, { 0x00e9, 0x82, 0x00 }, 445250199Sgrehan { 0x00ea, 0x88, 0x01 }, { 0x00ec, 0x8d, 0x00 }, 446250199Sgrehan { 0x00ed, 0xa1, 0x00 }, { 0x00ee, 0x8c, 0x00 }, 447250199Sgrehan { 0x00ef, 0x8b, 0x00 }, { 0x00f0, 0xeb, 0x00 }, 448250199Sgrehan { 0x00f1, 0xa4, 0x00 }, { 0x00f2, 0x95, 0x00 }, 449250199Sgrehan { 0x00f3, 0xa2, 0x00 }, { 0x00f4, 0x93, 0x00 }, 450250199Sgrehan { 0x00f6, 0x94, 0x00 }, { 0x00f7, 0xf6, 0x00 }, 451250199Sgrehan { 0x00f8, 0xed, 0x00 }, { 0x00f9, 0x97, 0x00 }, 452250199Sgrehan { 0x00fa, 0xa3, 0x00 }, { 0x00fb, 0x96, 0x00 }, 453250199Sgrehan { 0x00fc, 0x81, 0x00 }, { 0x00ff, 0x98, 0x00 }, 454250199Sgrehan { 0x013f, 0x4c, 0x00 }, { 0x0140, 0x6c, 0x00 }, 455250199Sgrehan { 0x0192, 0x9f, 0x00 }, { 0x0393, 0xe2, 0x00 }, 456250199Sgrehan { 0x0398, 0xe9, 0x00 }, { 0x03a3, 0xe4, 0x00 }, 457250199Sgrehan { 0x03a6, 0xe8, 0x00 }, { 0x03a9, 0xea, 0x00 }, 458250199Sgrehan { 0x03b1, 0xe0, 0x01 }, { 0x03b4, 0xeb, 0x00 }, 459250199Sgrehan { 0x03b5, 0xee, 0x00 }, { 0x03bc, 0xe6, 0x00 }, 460250199Sgrehan { 0x03c0, 0xe3, 0x00 }, { 0x03c3, 0xe5, 0x00 }, 461297635Ssephe { 0x03c4, 0xe7, 0x00 }, { 0x03c6, 0xed, 0x00 }, 462250199Sgrehan { 0x03d5, 0xed, 0x00 }, { 0x2010, 0x2d, 0x00 }, 463250199Sgrehan { 0x2014, 0x2d, 0x00 }, { 0x2018, 0x60, 0x00 }, 464297635Ssephe { 0x2019, 0x27, 0x00 }, { 0x201c, 0x22, 0x00 }, 465250199Sgrehan { 0x201d, 0x22, 0x00 }, { 0x2022, 0x07, 0x00 }, 466250199Sgrehan { 0x203c, 0x13, 0x00 }, { 0x207f, 0xfc, 0x00 }, 467250199Sgrehan { 0x20a7, 0x9e, 0x00 }, { 0x20ac, 0xee, 0x00 }, 468250199Sgrehan { 0x2126, 0xea, 0x00 }, { 0x2190, 0x1b, 0x00 }, 469250199Sgrehan { 0x2191, 0x18, 0x00 }, { 0x2192, 0x1a, 0x00 }, 470250199Sgrehan { 0x2193, 0x19, 0x00 }, { 0x2194, 0x1d, 0x00 }, 471296028Ssephe { 0x2195, 0x12, 0x00 }, { 0x21a8, 0x17, 0x00 }, 472250199Sgrehan { 0x2202, 0xeb, 0x00 }, { 0x2208, 0xee, 0x00 }, 473250199Sgrehan { 0x2211, 0xe4, 0x00 }, { 0x2212, 0x2d, 0x00 }, 474250199Sgrehan { 0x2219, 0xf9, 0x00 }, { 0x221a, 0xfb, 0x00 }, 475250199Sgrehan { 0x221e, 0xec, 0x00 }, { 0x221f, 0x1c, 0x00 }, 476250199Sgrehan { 0x2229, 0xef, 0x00 }, { 0x2248, 0xf7, 0x00 }, 477297635Ssephe { 0x2261, 0xf0, 0x00 }, { 0x2264, 0xf3, 0x00 }, 478250199Sgrehan { 0x2265, 0xf2, 0x00 }, { 0x2302, 0x7f, 0x00 }, 479250199Sgrehan { 0x2310, 0xa9, 0x00 }, { 0x2320, 0xf4, 0x00 }, 480297635Ssephe { 0x2321, 0xf5, 0x00 }, { 0x2500, 0xc4, 0x00 }, 481250199Sgrehan { 0x2502, 0xb3, 0x00 }, { 0x250c, 0xda, 0x00 }, 482250199Sgrehan { 0x2510, 0xbf, 0x00 }, { 0x2514, 0xc0, 0x00 }, 483250199Sgrehan { 0x2518, 0xd9, 0x00 }, { 0x251c, 0xc3, 0x00 }, 484250199Sgrehan { 0x2524, 0xb4, 0x00 }, { 0x252c, 0xc2, 0x00 }, 485250199Sgrehan { 0x2534, 0xc1, 0x00 }, { 0x253c, 0xc5, 0x00 }, 486250199Sgrehan { 0x2550, 0xcd, 0x00 }, { 0x2551, 0xba, 0x00 }, 487282212Swhu { 0x2552, 0xd5, 0x00 }, { 0x2553, 0xd6, 0x00 }, 488282212Swhu { 0x2554, 0xc9, 0x00 }, { 0x2555, 0xb8, 0x00 }, 489250199Sgrehan { 0x2556, 0xb7, 0x00 }, { 0x2557, 0xbb, 0x00 }, 490302610Ssephe { 0x2558, 0xd4, 0x00 }, { 0x2559, 0xd3, 0x00 }, 491302610Ssephe { 0x255a, 0xc8, 0x00 }, { 0x255b, 0xbe, 0x00 }, 492302610Ssephe { 0x255c, 0xbd, 0x00 }, { 0x255d, 0xbc, 0x00 }, 493294886Ssephe { 0x255e, 0xc6, 0x01 }, { 0x2560, 0xcc, 0x00 }, 494302610Ssephe { 0x2561, 0xb5, 0x00 }, { 0x2562, 0xb6, 0x00 }, 495250199Sgrehan { 0x2563, 0xb9, 0x00 }, { 0x2564, 0xd1, 0x01 }, 496282212Swhu { 0x2566, 0xcb, 0x00 }, { 0x2567, 0xcf, 0x00 }, 497282212Swhu { 0x2568, 0xd0, 0x00 }, { 0x2569, 0xca, 0x00 }, 498282212Swhu { 0x256a, 0xd8, 0x00 }, { 0x256b, 0xd7, 0x00 }, 499294886Ssephe { 0x256c, 0xce, 0x00 }, { 0x2580, 0xdf, 0x00 }, 500294886Ssephe { 0x2584, 0xdc, 0x00 }, { 0x2588, 0xdb, 0x00 }, 501294886Ssephe { 0x258c, 0xdd, 0x00 }, { 0x2590, 0xde, 0x00 }, 502294886Ssephe { 0x2591, 0xb0, 0x02 }, { 0x25a0, 0xfe, 0x00 }, 503250199Sgrehan { 0x25ac, 0x16, 0x00 }, 504250199Sgrehan { 0x25ae, 0xdb, 0x00 }, { 0x25b2, 0x1e, 0x00 }, 505250199Sgrehan { 0x25ba, 0x10, 0x00 }, { 0x25bc, 0x1f, 0x00 }, 506250199Sgrehan { 0x25c4, 0x11, 0x00 }, { 0x25cb, 0x09, 0x00 }, 507250199Sgrehan { 0x25d8, 0x08, 0x00 }, { 0x25d9, 0x0a, 0x00 }, 508250199Sgrehan { 0x263a, 0x01, 0x01 }, { 0x263c, 0x0f, 0x00 }, 509302610Ssephe { 0x2640, 0x0c, 0x00 }, { 0x2642, 0x0b, 0x00 }, 510302610Ssephe { 0x2660, 0x06, 0x00 }, { 0x2663, 0x05, 0x00 }, 511302610Ssephe { 0x2665, 0x03, 0x01 }, { 0x266a, 0x0d, 0x01 }, 512302610Ssephe}; 513302610Ssephe 514302610Ssephestatic void 515302610Ssephescteken_get_cp437(teken_char_t *c, int *attr) 516250199Sgrehan{ 517302610Ssephe int min, mid, max; 518302610Ssephe 519302610Ssephe min = 0; 520250199Sgrehan max = (sizeof(cp437table) / sizeof(struct unicp437)) - 1; 521302610Ssephe 522302610Ssephe if (*c < cp437table[0].unicode_base || 523302610Ssephe *c > cp437table[max].unicode_base + cp437table[max].length) 524302610Ssephe goto bad; 525302610Ssephe 526302610Ssephe while (max >= min) { 527302610Ssephe mid = (min + max) / 2; 528302610Ssephe if (*c < cp437table[mid].unicode_base) { 529302610Ssephe max = mid - 1; 530302610Ssephe } else if (*c > cp437table[mid].unicode_base + 531302610Ssephe cp437table[mid].length) { 532302610Ssephe min = mid + 1; 533302610Ssephe } else { 534250199Sgrehan *c -= cp437table[mid].unicode_base; 535250199Sgrehan *c += cp437table[mid].cp437_base; 536250199Sgrehan return; 537250199Sgrehan } 538250199Sgrehan } 539250199Sgrehanbad: 540250199Sgrehan /* Character not present in CP437. */ 541250199Sgrehan *attr = (FG_RED|BG_BLACK) << 8; 542250199Sgrehan *c = '?'; 543250199Sgrehan} 544250199Sgrehan#endif /* TEKEN_UTF8 */ 545250199Sgrehan 546256350Sgrehanstatic void 547256350Sgrehanscteken_putchar(void *arg, const teken_pos_t *tp, teken_char_t c, 548282212Swhu const teken_attr_t *a) 549250199Sgrehan{ 550282212Swhu scr_stat *scp = arg; 551282212Swhu u_char *map; 552282212Swhu u_char ch; 553282212Swhu vm_offset_t p; 554282212Swhu int cursor, attr; 555282212Swhu 556282212Swhu /* 557282212Swhu * No support for printing right hand sides for CJK fullwidth 558282212Swhu * characters. Simply print a space and assume that the left 559282212Swhu * hand side describes the entire character. 560282212Swhu */ 561282212Swhu attr = scteken_attr(a) << 8; 562282212Swhu if (a->ta_format & TF_CJK_RIGHT) 563282212Swhu c = ' '; 564282212Swhu#ifdef TEKEN_UTF8 565282212Swhu scteken_get_cp437(&c, &attr); 566250199Sgrehan#endif /* TEKEN_UTF8 */ 567282212Swhu ch = c; 568250199Sgrehan 569282212Swhu map = scp->sc->scr_map; 570282212Swhu 571282212Swhu cursor = tp->tp_row * scp->xsize + tp->tp_col; 572282212Swhu p = sc_vtb_pointer(&scp->vtb, cursor); 573282212Swhu sc_vtb_putchar(&scp->vtb, p, map[ch], attr); 574250199Sgrehan 575282212Swhu mark_for_update(scp, cursor); 576282212Swhu /* 577282212Swhu * XXX: Why do we need this? Only marking `cursor' should be 578282212Swhu * enough. Without this line, we get artifacts. 579250199Sgrehan */ 580250199Sgrehan mark_for_update(scp, imin(cursor + 1, scp->xsize * scp->ysize - 1)); 581250199Sgrehan} 582250199Sgrehan 583250199Sgrehanstatic void 584250199Sgrehanscteken_fill(void *arg, const teken_rect_t *r, teken_char_t c, 585250199Sgrehan const teken_attr_t *a) 586250199Sgrehan{ 587250199Sgrehan scr_stat *scp = arg; 588250199Sgrehan u_char *map; 589250199Sgrehan u_char ch; 590250199Sgrehan unsigned int width; 591250199Sgrehan int attr, row; 592250199Sgrehan 593250199Sgrehan attr = scteken_attr(a) << 8; 594250199Sgrehan#ifdef TEKEN_UTF8 595250199Sgrehan scteken_get_cp437(&c, &attr); 596250199Sgrehan#endif /* TEKEN_UTF8 */ 597250199Sgrehan ch = c; 598282212Swhu 599250199Sgrehan map = scp->sc->scr_map; 600250199Sgrehan 601250199Sgrehan if (r->tr_begin.tp_col == 0 && r->tr_end.tp_col == scp->xsize) { 602250199Sgrehan /* Single contiguous region to fill. */ 603250199Sgrehan sc_vtb_erase(&scp->vtb, r->tr_begin.tp_row * scp->xsize, 604250199Sgrehan (r->tr_end.tp_row - r->tr_begin.tp_row) * scp->xsize, 605250199Sgrehan map[ch], attr); 606250199Sgrehan } else { 607250199Sgrehan /* Fill display line by line. */ 608250199Sgrehan width = r->tr_end.tp_col - r->tr_begin.tp_col; 609250199Sgrehan 610250199Sgrehan for (row = r->tr_begin.tp_row; row < r->tr_end.tp_row; row++) { 611250199Sgrehan sc_vtb_erase(&scp->vtb, r->tr_begin.tp_row * 612250199Sgrehan scp->xsize + r->tr_begin.tp_col, 613250199Sgrehan width, map[ch], attr); 614250199Sgrehan } 615250199Sgrehan } 616250199Sgrehan 617250199Sgrehan /* Mark begin and end positions to be refreshed. */ 618250199Sgrehan mark_for_update(scp, 619250199Sgrehan r->tr_begin.tp_row * scp->xsize + r->tr_begin.tp_col); 620250199Sgrehan mark_for_update(scp, 621250199Sgrehan (r->tr_end.tp_row - 1) * scp->xsize + (r->tr_end.tp_col - 1)); 622282212Swhu sc_remove_cutmarking(scp); 623282212Swhu} 624250199Sgrehan 625250199Sgrehanstatic void 626282212Swhuscteken_copy(void *arg, const teken_rect_t *r, const teken_pos_t *p) 627250199Sgrehan{ 628250199Sgrehan scr_stat *scp = arg; 629250199Sgrehan unsigned int width; 630250199Sgrehan int src, dst, end; 631250199Sgrehan 632250199Sgrehan#ifndef SC_NO_HISTORY 633250199Sgrehan /* 634250199Sgrehan * We count a line of input as history if we perform a copy of 635250199Sgrehan * one whole line upward. In other words: if a line of text gets 636250199Sgrehan * overwritten by a rectangle that's right below it. 637250199Sgrehan */ 638250199Sgrehan if (scp->history != NULL && 639250199Sgrehan r->tr_begin.tp_col == 0 && r->tr_end.tp_col == scp->xsize && 640250199Sgrehan r->tr_begin.tp_row == p->tp_row + 1) { 641250199Sgrehan sc_hist_save_one_line(scp, p->tp_row); 642250199Sgrehan } 643250199Sgrehan#endif 644250199Sgrehan 645250199Sgrehan if (r->tr_begin.tp_col == 0 && r->tr_end.tp_col == scp->xsize) { 646250199Sgrehan /* Single contiguous region to copy. */ 647250199Sgrehan sc_vtb_move(&scp->vtb, r->tr_begin.tp_row * scp->xsize, 648282212Swhu p->tp_row * scp->xsize, 649250199Sgrehan (r->tr_end.tp_row - r->tr_begin.tp_row) * scp->xsize); 650294705Ssephe } else { 651250199Sgrehan /* Copy line by line. */ 652294705Ssephe width = r->tr_end.tp_col - r->tr_begin.tp_col; 653250199Sgrehan 654250199Sgrehan if (p->tp_row < r->tr_begin.tp_row) { 655250199Sgrehan /* Copy from top to bottom. */ 656250199Sgrehan src = r->tr_begin.tp_row * scp->xsize + 657250199Sgrehan r->tr_begin.tp_col; 658250199Sgrehan end = r->tr_end.tp_row * scp->xsize + 659250199Sgrehan r->tr_end.tp_col; 660250199Sgrehan dst = p->tp_row * scp->xsize + p->tp_col; 661250199Sgrehan 662250199Sgrehan while (src < end) { 663250199Sgrehan sc_vtb_move(&scp->vtb, src, dst, width); 664294705Ssephe 665294705Ssephe src += scp->xsize; 666294705Ssephe dst += scp->xsize; 667250199Sgrehan } 668250199Sgrehan } else { 669250199Sgrehan /* Copy from bottom to top. */ 670250199Sgrehan src = (r->tr_end.tp_row - 1) * scp->xsize + 671250199Sgrehan r->tr_begin.tp_col; 672294705Ssephe end = r->tr_begin.tp_row * scp->xsize + 673294705Ssephe r->tr_begin.tp_col; 674250199Sgrehan dst = (p->tp_row + r->tr_end.tp_row - 675250199Sgrehan r->tr_begin.tp_row - 1) * scp->xsize + p->tp_col; 676250199Sgrehan 677250199Sgrehan while (src >= end) { 678250199Sgrehan sc_vtb_move(&scp->vtb, src, dst, width); 679250199Sgrehan 680250199Sgrehan src -= scp->xsize; 681294705Ssephe dst -= scp->xsize; 682294705Ssephe } 683250199Sgrehan } 684294705Ssephe } 685294705Ssephe 686250199Sgrehan /* Mark begin and end positions to be refreshed. */ 687294705Ssephe mark_for_update(scp, 688294705Ssephe p->tp_row * scp->xsize + p->tp_col); 689294705Ssephe mark_for_update(scp, 690294705Ssephe (p->tp_row + r->tr_end.tp_row - r->tr_begin.tp_row - 1) * 691282212Swhu scp->xsize + 692250199Sgrehan (p->tp_col + r->tr_end.tp_col - r->tr_begin.tp_col - 1)); 693250199Sgrehan sc_remove_cutmarking(scp); 694282212Swhu} 695250199Sgrehan 696250199Sgrehanstatic void 697250199Sgrehanscteken_param(void *arg, int cmd, unsigned int value) 698250199Sgrehan{ 699250199Sgrehan scr_stat *scp = arg; 700250199Sgrehan 701250199Sgrehan switch (cmd) { 702250199Sgrehan case TP_SHOWCURSOR: 703250199Sgrehan if (value) { 704250199Sgrehan sc_change_cursor_shape(scp, 705250199Sgrehan CONS_RESET_CURSOR|CONS_LOCAL_CURSOR, -1, -1); 706250199Sgrehan } else { 707250199Sgrehan sc_change_cursor_shape(scp, 708250199Sgrehan CONS_HIDDEN_CURSOR|CONS_LOCAL_CURSOR, -1, -1); 709250199Sgrehan } 710250199Sgrehan break; 711250199Sgrehan case TP_SWITCHVT: 712250199Sgrehan sc_switch_scr(scp->sc, value); 713250199Sgrehan break; 714250199Sgrehan case TP_SETBELLPD: 715282212Swhu scp->bell_pitch = TP_SETBELLPD_PITCH(value); 716250199Sgrehan scp->bell_duration = TP_SETBELLPD_DURATION(value); 717250199Sgrehan break; 718250199Sgrehan case TP_MOUSE: 719250199Sgrehan scp->mouse_level = value; 720250199Sgrehan break; 721250199Sgrehan } 722250199Sgrehan} 723250199Sgrehan 724250199Sgrehanstatic void 725250199Sgrehanscteken_respond(void *arg, const void *buf, size_t len) 726250199Sgrehan{ 727250199Sgrehan scr_stat *scp = arg; 728250199Sgrehan 729250199Sgrehan sc_respond(scp, buf, len, 0); 730250199Sgrehan} 731250199Sgrehan