[libteken] Initial import.
This is a fork of libteken, which originally lived in
domokit/third_party
Change-Id: I04420463a526d8f789bbeef4c8d91a7a06894b7f
diff --git a/AUTHORS b/AUTHORS
deleted file mode 100644
index c2a4eac..0000000
--- a/AUTHORS
+++ /dev/null
@@ -1,8 +0,0 @@
-# This is the list of Fuchsia Authors.
-
-# Names should be added to this file as one of
-# Organization's name
-# Individual's name <submission email address>
-# Individual's name <submission email address> <email2> <emailN>
-
-Google Inc.
diff --git a/BUILD.gn b/BUILD.gn
new file mode 100644
index 0000000..0d46c90
--- /dev/null
+++ b/BUILD.gn
@@ -0,0 +1,17 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("libteken") {
+ sources = [
+ "teken/teken.c",
+ "teken/teken.h",
+ "teken/teken_scs.h",
+ "teken/teken_state.h",
+ "teken/teken_subr.h",
+ "teken/teken_subr_compat.h",
+ "teken/teken_wcwidth.h",
+ ]
+
+ defines = [ "__unused=__attribute__((unused))" ]
+}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
deleted file mode 100644
index 81e2938..0000000
--- a/CONTRIBUTING.md
+++ /dev/null
@@ -1,9 +0,0 @@
-This repository accepts contributions using Gerrit.
-
-Instructions for using Gerrit:
-
- * https://gerrit-review.googlesource.com/Documentation/
-
-Before we can land your change, you need to sign the Google CLA:
-
- * https://cla.developers.google.com/
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644
index 0000000..8f274b3
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,126 @@
+# $FreeBSD: head/COPYRIGHT 260125 2013-12-31 12:18:10Z gjb $
+# @(#)COPYRIGHT 8.2 (Berkeley) 3/21/94
+
+The compilation of software known as FreeBSD is distributed under the
+following terms:
+
+Copyright (c) 1992-2014 The FreeBSD Project. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+The 4.4BSD and 4.4BSD-Lite software is distributed under the following
+terms:
+
+All of the documentation and software included in the 4.4BSD and 4.4BSD-Lite
+Releases is copyrighted by The Regents of the University of California.
+
+Copyright 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
+ The Regents of the University of California. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgement:
+This product includes software developed by the University of
+California, Berkeley and its contributors.
+4. Neither the name of the University nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+The Institute of Electrical and Electronics Engineers and the American
+National Standards Committee X3, on Information Processing Systems have
+given us permission to reprint portions of their documentation.
+
+In the following statement, the phrase ``this text'' refers to portions
+of the system documentation.
+
+Portions of this text are reprinted and reproduced in electronic form in
+the second BSD Networking Software Release, from IEEE Std 1003.1-1988, IEEE
+Standard Portable Operating System Interface for Computer Environments
+(POSIX), copyright C 1988 by the Institute of Electrical and Electronics
+Engineers, Inc. In the event of any discrepancy between these versions
+and the original IEEE Standard, the original IEEE Standard is the referee
+document.
+
+In the following statement, the phrase ``This material'' refers to portions
+of the system documentation.
+
+This material is reproduced with permission from American National
+Standards Committee X3, on Information Processing Systems. Computer and
+Business Equipment Manufacturers Association (CBEMA), 311 First St., NW,
+Suite 500, Washington, DC 20001-2178. The developmental work of
+Programming Language C was completed by the X3J11 Technical Committee.
+
+The views and conclusions contained in the software and documentation are
+those of the authors and should not be interpreted as representing official
+policies, either expressed or implied, of the Regents of the University
+of California.
+
+
+NOTE: The copyright of UC Berkeley's Berkeley Software Distribution ("BSD")
+source has been updated. The copyright addendum may be found at
+ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change and is
+included below.
+
+July 22, 1999
+
+To All Licensees, Distributors of Any Version of BSD:
+
+As you know, certain of the Berkeley Software Distribution ("BSD") source
+code files require that further distributions of products containing all or
+portions of the software, acknowledge within their advertising materials
+that such products contain software developed by UC Berkeley and its
+contributors.
+
+Specifically, the provision reads:
+
+" * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors."
+
+Effective immediately, licensees and distributors are no longer required to
+include the acknowledgement within advertising materials. Accordingly, the
+foregoing paragraph of those BSD Unix files containing it is hereby deleted
+in its entirety.
+
+William Hoskins
+Director, Office of Technology Licensing
+University of California, Berkeley
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index ac6402f..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
index 8b90b74..93cbbc1 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,24 @@
-Fuchsia Open Source Template Repository
-=======================================
+Name: libteken
+URL: svn://svn.FreeBSD.org/base/head/sys/teken/
+Version: r276292
+License: BSD
+License File: COPYRIGHT
+Security Critical: no
-This repository is a template that we will use when creating new open source
-repositories for Fuchsia.
+Description:
+This is libteken from FreeBSD, a VT100-ish terminal emulator library.
+
+It was obtained as follows (from this directory):
+
+ svn export svn://svn.FreeBSD.org/base/head/sys/teken/@276292
+ svn export svn://svn.FreeBSD.org/base/head/COPYRIGHT@276292
+
+Local modifications:
+* teken/teken_state.h: manually generated (from the teken subdirectory) using:
+ |awk -f gensequences sequences > teken_state.h|.
+* teken/teken.h: |#include <stdint.h>|.
+* teken/teken.h: |extern "C"| guards added for C++.
+* teken/gensequences: made executable, to placate checkperms.py.
+* teken/{demo, libteken, stress}: removed.
+* teken.c: remove sys/cdefs.h to fix fnl/musl build
+ (http://wiki.musl-libc.org/wiki/FAQ#Q:_I.27m_trying_to_compile_something_against_musl_and_I_get_error_messages_about_sys.2Fcdefs.h)
diff --git a/teken/gensequences b/teken/gensequences
new file mode 100755
index 0000000..83a3d10
--- /dev/null
+++ b/teken/gensequences
@@ -0,0 +1,157 @@
+#!/usr/bin/awk -f
+
+#-
+# Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD: head/sys/teken/gensequences 223574 2011-06-26 18:25:10Z ed $
+
+function die(msg) {
+ print msg;
+ exit 1;
+}
+
+function cchar(str) {
+ if (str == "^[")
+ return "\\x1B";
+
+ return str;
+}
+
+BEGIN {
+FS = "\t+"
+
+while (getline > 0) {
+ if (NF == 0 || $1 ~ /^#/)
+ continue;
+
+ if (NF != 3 && NF != 4)
+ die("Invalid line layout: " NF " columns");
+
+ split($3, sequence, " +");
+ nsequences = 0;
+ for (s in sequence)
+ nsequences++;
+
+ prefix = "";
+ l_prefix_name[""] = "teken_state_init";
+ for (i = 1; i < nsequences; i++) {
+ n = prefix sequence[i];
+ l_prefix_parent[n] = prefix;
+ l_prefix_suffix[n] = sequence[i];
+ if (!l_prefix_name[n])
+ l_prefix_name[n] = "teken_state_" ++npr;
+ prefix = n;
+ }
+
+ suffix = sequence[nsequences];
+ cmd = prefix suffix;
+
+ # Fill lists
+ if (l_cmd_name[cmd] != "")
+ die(cmd " already exists");
+ l_cmd_prefix[cmd] = prefix;
+ l_cmd_suffix[cmd] = suffix;
+ l_cmd_args[cmd] = $4;
+ l_cmd_abbr[cmd] = $1;
+ l_cmd_name[cmd] = $2;
+ l_cmd_c_name[cmd] = "teken_subr_" tolower($2);
+ gsub(" ", "_", l_cmd_c_name[cmd]);
+
+ if ($4 != "")
+ l_prefix_numbercmds[prefix]++;
+}
+
+print "/* Generated file. Do not edit. */";
+print "";
+
+for (p in l_prefix_name) {
+ if (l_prefix_name[p] != "teken_state_init")
+ print "static teken_state_t " l_prefix_name[p] ";";
+}
+
+for (p in l_prefix_name) {
+ print "";
+ print "/* '" p "' */";
+ print "static void";
+ print l_prefix_name[p] "(teken_t *t, teken_char_t c)";
+ print "{";
+
+ if (l_prefix_numbercmds[p] > 0) {
+ print "";
+ print "\tif (teken_state_numbers(t, c))";
+ print "\t\treturn;";
+ }
+
+ print "";
+ print "\tswitch (c) {";
+ for (c in l_cmd_prefix) {
+ if (l_cmd_prefix[c] != p)
+ continue;
+
+ print "\tcase '" cchar(l_cmd_suffix[c]) "': /* " l_cmd_abbr[c] ": " l_cmd_name[c] " */";
+
+ if (l_cmd_args[c] == "v") {
+ print "\t\t" l_cmd_c_name[c] "(t, t->t_curnum, t->t_nums);";
+ } else {
+ printf "\t\t%s(t", l_cmd_c_name[c];
+ split(l_cmd_args[c], args, " ");
+ for (a = 1; args[a] != ""; a++) {
+ if (args[a] == "n")
+ printf ", (t->t_curnum < %d || t->t_nums[%d] == 0) ? 1 : t->t_nums[%d]", a, (a - 1), (a - 1);
+ else if (args[a] == "r")
+ printf ", t->t_curnum < %d ? 0 : t->t_nums[%d]", a, (a - 1);
+ else
+ die("Invalid argument type: " args[a]);
+ }
+ print ");";
+ }
+ print "\t\tbreak;";
+ }
+ for (pc in l_prefix_parent) {
+ if (l_prefix_parent[pc] != p)
+ continue;
+ print "\tcase '" cchar(l_prefix_suffix[pc]) "':";
+ print "\t\tteken_state_switch(t, " l_prefix_name[pc] ");";
+ print "\t\treturn;";
+ }
+
+ print "\tdefault:";
+ if (l_prefix_name[p] == "teken_state_init") {
+ print "\t\tteken_subr_regular_character(t, c);";
+ } else {
+ print "\t\tteken_printf(\"Unsupported sequence in " l_prefix_name[p] ": %u\\n\", (unsigned int)c);";
+ }
+ print "\t\tbreak;";
+
+ print "\t}";
+
+ if (l_prefix_name[p] != "teken_state_init") {
+ print "";
+ print "\tteken_state_switch(t, teken_state_init);";
+ }
+ print "}";
+}
+
+}
diff --git a/teken/sequences b/teken/sequences
new file mode 100644
index 0000000..080657a
--- /dev/null
+++ b/teken/sequences
@@ -0,0 +1,113 @@
+#-
+# Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD: head/sys/teken/sequences 214817 2010-11-05 00:56:21Z ed $
+
+# File format is as follows:
+# Abbr Abbreviation of sequence name
+# Name Sequence name (will be converted to C function name)
+# Sequence Bytes that form the sequence
+# Arguments Standard value of arguments passed to this sequence
+# - `n' non-zero number (0 gets converted to 1)
+# - `r' regular numeric argument
+# - `v' means a variable number of arguments
+
+# Abbr Name Sequence Arguments
+CBT Cursor Backward Tabulation ^[ [ Z n
+CHT Cursor Forward Tabulation ^[ [ I n
+CNL Cursor Next Line ^[ [ E n
+CPL Cursor Previous Line ^[ [ F n
+CPR Cursor Position Report ^[ [ n r
+CUB Cursor Backward ^[ [ D n
+CUD Cursor Down ^[ [ B n
+CUD Cursor Down ^[ [ e n
+CUF Cursor Forward ^[ [ C n
+CUF Cursor Forward ^[ [ a n
+CUP Cursor Position ^[ [ H n n
+CUP Cursor Position ^[ [ f n n
+CUU Cursor Up ^[ [ A n
+DA1 Primary Device Attributes ^[ [ c r
+DA2 Secondary Device Attributes ^[ [ > c r
+DC Delete character ^[ [ P n
+DCS Device Control String ^[ P
+DECALN Alignment test ^[ # 8
+DECDHL Double Height Double Width Line Top ^[ # 3
+DECDHL Double Height Double Width Line Bottom ^[ # 4
+DECDWL Single Height Double Width Line ^[ # 6
+DECKPAM Keypad application mode ^[ =
+DECKPNM Keypad numeric mode ^[ >
+DECRC Restore cursor ^[ 8
+DECRC Restore cursor ^[ [ u
+DECRM Reset DEC mode ^[ [ ? l r
+DECSC Save cursor ^[ 7
+DECSC Save cursor ^[ [ s
+DECSM Set DEC mode ^[ [ ? h r
+DECSTBM Set top and bottom margins ^[ [ r r r
+DECSWL Single Height Single Width Line ^[ # 5
+DL Delete line ^[ [ M n
+DSR Device Status Report ^[ [ ? n r
+ECH Erase character ^[ [ X n
+ED Erase display ^[ [ J r
+EL Erase line ^[ [ K r
+G0SCS0 G0 SCS Special Graphics ^[ ( 0
+G0SCS1 G0 SCS US ASCII ^[ ( 1
+G0SCS2 G0 SCS Special Graphics ^[ ( 2
+G0SCSA G0 SCS UK National ^[ ( A
+G0SCSB G0 SCS US ASCII ^[ ( B
+G1SCS0 G1 SCS Special Graphics ^[ ) 0
+G1SCS1 G1 SCS US ASCII ^[ ) 1
+G1SCS2 G1 SCS Special Graphics ^[ ) 2
+G1SCSA G1 SCS UK National ^[ ) A
+G1SCSB G1 SCS US ASCII ^[ ) B
+HPA Horizontal Position Absolute ^[ [ G n
+HPA Horizontal Position Absolute ^[ [ ` n
+HTS Horizontal Tab Set ^[ H
+ICH Insert character ^[ [ @ n
+IL Insert line ^[ [ L n
+IND Index ^[ D
+NEL Next line ^[ E
+OSC Operating System Command ^[ ]
+RI Reverse index ^[ M
+RIS Reset to Initial State ^[ c
+RM Reset Mode ^[ [ l r
+SD Pan Up ^[ [ T n
+SGR Set Graphic Rendition ^[ [ m v
+SM Set Mode ^[ [ h r
+ST String Terminator ^[ \\
+SU Pan Down ^[ [ S n
+TBC Tab Clear ^[ [ g r
+VPA Vertical Position Absolute ^[ [ d n
+
+# Cons25 compatibility sequences
+C25ADBG Cons25 set adapter background ^[ [ = G r
+C25ADFG Cons25 set adapter foreground ^[ [ = F r
+C25BLPD Cons25 set bell pitch duration ^[ [ = B r r
+C25CURS Cons25 set cursor type ^[ [ = S r
+C25MODE Cons25 set terminal mode ^[ [ = T r
+C25SGR Cons25 set graphic rendition ^[ [ x r r
+C25VTSW Cons25 switch virtual terminal ^[ [ z r
+
+# VT52 compatibility
+#DECID VT52 DECID ^[ Z
diff --git a/teken/teken.c b/teken/teken.c
new file mode 100644
index 0000000..b1c9d15
--- /dev/null
+++ b/teken/teken.c
@@ -0,0 +1,557 @@
+/*-
+ * Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/sys/teken/teken.c 261551 2014-02-06 13:28:06Z ray $
+ */
+
+#if defined(__FreeBSD__) && defined(_KERNEL)
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/systm.h>
+#define teken_assert(x) MPASS(x)
+#else /* !(__FreeBSD__ && _KERNEL) */
+#include <sys/types.h>
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#define teken_assert(x) assert(x)
+#endif /* __FreeBSD__ && _KERNEL */
+
+/* debug messages */
+#define teken_printf(x,...)
+
+/* Private flags for t_stateflags. */
+#define TS_FIRSTDIGIT 0x0001 /* First numeric digit in escape sequence. */
+#define TS_INSERT 0x0002 /* Insert mode. */
+#define TS_AUTOWRAP 0x0004 /* Autowrap. */
+#define TS_ORIGIN 0x0008 /* Origin mode. */
+#define TS_WRAPPED 0x0010 /* Next character should be printed on col 0. */
+#define TS_8BIT 0x0020 /* UTF-8 disabled. */
+#define TS_CONS25 0x0040 /* cons25 emulation. */
+#define TS_INSTRING 0x0080 /* Inside string. */
+#define TS_CURSORKEYS 0x0100 /* Cursor keys mode. */
+
+/* Character that blanks a cell. */
+#define BLANK ' '
+
+#include "teken.h"
+#include "teken_wcwidth.h"
+#include "teken_scs.h"
+
+static teken_state_t teken_state_init;
+
+/*
+ * Wrappers for hooks.
+ */
+
+static inline void
+teken_funcs_bell(teken_t *t)
+{
+
+ t->t_funcs->tf_bell(t->t_softc);
+}
+
+static inline void
+teken_funcs_cursor(teken_t *t)
+{
+
+ teken_assert(t->t_cursor.tp_row < t->t_winsize.tp_row);
+ teken_assert(t->t_cursor.tp_col < t->t_winsize.tp_col);
+
+ t->t_funcs->tf_cursor(t->t_softc, &t->t_cursor);
+}
+
+static inline void
+teken_funcs_putchar(teken_t *t, const teken_pos_t *p, teken_char_t c,
+ const teken_attr_t *a)
+{
+
+ teken_assert(p->tp_row < t->t_winsize.tp_row);
+ teken_assert(p->tp_col < t->t_winsize.tp_col);
+
+ t->t_funcs->tf_putchar(t->t_softc, p, c, a);
+}
+
+static inline void
+teken_funcs_fill(teken_t *t, const teken_rect_t *r,
+ const teken_char_t c, const teken_attr_t *a)
+{
+
+ teken_assert(r->tr_end.tp_row > r->tr_begin.tp_row);
+ teken_assert(r->tr_end.tp_row <= t->t_winsize.tp_row);
+ teken_assert(r->tr_end.tp_col > r->tr_begin.tp_col);
+ teken_assert(r->tr_end.tp_col <= t->t_winsize.tp_col);
+
+ t->t_funcs->tf_fill(t->t_softc, r, c, a);
+}
+
+static inline void
+teken_funcs_copy(teken_t *t, const teken_rect_t *r, const teken_pos_t *p)
+{
+
+ teken_assert(r->tr_end.tp_row > r->tr_begin.tp_row);
+ teken_assert(r->tr_end.tp_row <= t->t_winsize.tp_row);
+ teken_assert(r->tr_end.tp_col > r->tr_begin.tp_col);
+ teken_assert(r->tr_end.tp_col <= t->t_winsize.tp_col);
+ teken_assert(p->tp_row + (r->tr_end.tp_row - r->tr_begin.tp_row) <= t->t_winsize.tp_row);
+ teken_assert(p->tp_col + (r->tr_end.tp_col - r->tr_begin.tp_col) <= t->t_winsize.tp_col);
+
+ t->t_funcs->tf_copy(t->t_softc, r, p);
+}
+
+static inline void
+teken_funcs_param(teken_t *t, int cmd, unsigned int value)
+{
+
+ t->t_funcs->tf_param(t->t_softc, cmd, value);
+}
+
+static inline void
+teken_funcs_respond(teken_t *t, const void *buf, size_t len)
+{
+
+ t->t_funcs->tf_respond(t->t_softc, buf, len);
+}
+
+#include "teken_subr.h"
+#include "teken_subr_compat.h"
+
+/*
+ * Programming interface.
+ */
+
+void
+teken_init(teken_t *t, const teken_funcs_t *tf, void *softc)
+{
+ teken_pos_t tp = { .tp_row = 24, .tp_col = 80 };
+
+ t->t_funcs = tf;
+ t->t_softc = softc;
+
+ t->t_nextstate = teken_state_init;
+ t->t_stateflags = 0;
+ t->t_utf8_left = 0;
+
+ t->t_defattr.ta_format = 0;
+ t->t_defattr.ta_fgcolor = TC_WHITE;
+ t->t_defattr.ta_bgcolor = TC_BLACK;
+ teken_subr_do_reset(t);
+
+ teken_set_winsize(t, &tp);
+}
+
+static void
+teken_input_char(teken_t *t, teken_char_t c)
+{
+
+ /*
+ * There is no support for DCS and OSC. Just discard strings
+ * until we receive characters that may indicate string
+ * termination.
+ */
+ if (t->t_stateflags & TS_INSTRING) {
+ switch (c) {
+ case '\x1B':
+ t->t_stateflags &= ~TS_INSTRING;
+ break;
+ case '\a':
+ t->t_stateflags &= ~TS_INSTRING;
+ return;
+ default:
+ return;
+ }
+ }
+
+ switch (c) {
+ case '\0':
+ break;
+ case '\a':
+ teken_subr_bell(t);
+ break;
+ case '\b':
+ teken_subr_backspace(t);
+ break;
+ case '\n':
+ case '\x0B':
+ teken_subr_newline(t);
+ break;
+ case '\x0C':
+ teken_subr_newpage(t);
+ break;
+ case '\x0E':
+ if (t->t_stateflags & TS_CONS25)
+ t->t_nextstate(t, c);
+ else
+ t->t_curscs = 1;
+ break;
+ case '\x0F':
+ if (t->t_stateflags & TS_CONS25)
+ t->t_nextstate(t, c);
+ else
+ t->t_curscs = 0;
+ break;
+ case '\r':
+ teken_subr_carriage_return(t);
+ break;
+ case '\t':
+ teken_subr_horizontal_tab(t);
+ break;
+ default:
+ t->t_nextstate(t, c);
+ break;
+ }
+
+ /* Post-processing assertions. */
+ teken_assert(t->t_cursor.tp_row >= t->t_originreg.ts_begin);
+ teken_assert(t->t_cursor.tp_row < t->t_originreg.ts_end);
+ teken_assert(t->t_cursor.tp_row < t->t_winsize.tp_row);
+ teken_assert(t->t_cursor.tp_col < t->t_winsize.tp_col);
+ teken_assert(t->t_saved_cursor.tp_row < t->t_winsize.tp_row);
+ teken_assert(t->t_saved_cursor.tp_col < t->t_winsize.tp_col);
+ teken_assert(t->t_scrollreg.ts_end <= t->t_winsize.tp_row);
+ teken_assert(t->t_scrollreg.ts_begin < t->t_scrollreg.ts_end);
+ /* Origin region has to be window size or the same as scrollreg. */
+ teken_assert((t->t_originreg.ts_begin == t->t_scrollreg.ts_begin &&
+ t->t_originreg.ts_end == t->t_scrollreg.ts_end) ||
+ (t->t_originreg.ts_begin == 0 &&
+ t->t_originreg.ts_end == t->t_winsize.tp_row));
+}
+
+static void
+teken_input_byte(teken_t *t, unsigned char c)
+{
+
+ /*
+ * UTF-8 handling.
+ */
+ if ((c & 0x80) == 0x00 || t->t_stateflags & TS_8BIT) {
+ /* One-byte sequence. */
+ t->t_utf8_left = 0;
+ teken_input_char(t, c);
+ } else if ((c & 0xe0) == 0xc0) {
+ /* Two-byte sequence. */
+ t->t_utf8_left = 1;
+ t->t_utf8_partial = c & 0x1f;
+ } else if ((c & 0xf0) == 0xe0) {
+ /* Three-byte sequence. */
+ t->t_utf8_left = 2;
+ t->t_utf8_partial = c & 0x0f;
+ } else if ((c & 0xf8) == 0xf0) {
+ /* Four-byte sequence. */
+ t->t_utf8_left = 3;
+ t->t_utf8_partial = c & 0x07;
+ } else if ((c & 0xc0) == 0x80) {
+ if (t->t_utf8_left == 0)
+ return;
+ t->t_utf8_left--;
+ t->t_utf8_partial = (t->t_utf8_partial << 6) | (c & 0x3f);
+ if (t->t_utf8_left == 0) {
+ teken_printf("Got UTF-8 char %x\n", t->t_utf8_partial);
+ teken_input_char(t, t->t_utf8_partial);
+ }
+ }
+}
+
+void
+teken_input(teken_t *t, const void *buf, size_t len)
+{
+ const char *c = buf;
+
+ while (len-- > 0)
+ teken_input_byte(t, *c++);
+}
+
+const teken_pos_t *
+teken_get_cursor(teken_t *t)
+{
+
+ return (&t->t_cursor);
+}
+
+void
+teken_set_cursor(teken_t *t, const teken_pos_t *p)
+{
+
+ /* XXX: bounds checking with originreg! */
+ teken_assert(p->tp_row < t->t_winsize.tp_row);
+ teken_assert(p->tp_col < t->t_winsize.tp_col);
+
+ t->t_cursor = *p;
+}
+
+const teken_attr_t *
+teken_get_curattr(teken_t *t)
+{
+
+ return (&t->t_curattr);
+}
+
+void
+teken_set_curattr(teken_t *t, const teken_attr_t *a)
+{
+
+ t->t_curattr = *a;
+}
+
+const teken_attr_t *
+teken_get_defattr(teken_t *t)
+{
+
+ return (&t->t_defattr);
+}
+
+void
+teken_set_defattr(teken_t *t, const teken_attr_t *a)
+{
+
+ t->t_curattr = t->t_saved_curattr = t->t_defattr = *a;
+}
+
+const teken_pos_t *
+teken_get_winsize(teken_t *t)
+{
+
+ return (&t->t_winsize);
+}
+
+static void
+teken_trim_cursor_pos(teken_t *t, const teken_pos_t *new)
+{
+ const teken_pos_t *cur;
+
+ cur = &t->t_winsize;
+
+ if (cur->tp_row < new->tp_row || cur->tp_col < new->tp_col)
+ return;
+ if (t->t_cursor.tp_row >= new->tp_row)
+ t->t_cursor.tp_row = new->tp_row - 1;
+ if (t->t_cursor.tp_col >= new->tp_col)
+ t->t_cursor.tp_col = new->tp_col - 1;
+}
+
+void
+teken_set_winsize(teken_t *t, const teken_pos_t *p)
+{
+
+ teken_trim_cursor_pos(t, p);
+ t->t_winsize = *p;
+ teken_subr_do_reset(t);
+}
+
+void
+teken_set_winsize_noreset(teken_t *t, const teken_pos_t *p)
+{
+
+ teken_trim_cursor_pos(t, p);
+ t->t_winsize = *p;
+ teken_subr_do_resize(t);
+}
+
+void
+teken_set_8bit(teken_t *t)
+{
+
+ t->t_stateflags |= TS_8BIT;
+}
+
+void
+teken_set_cons25(teken_t *t)
+{
+
+ t->t_stateflags |= TS_CONS25;
+}
+
+/*
+ * State machine.
+ */
+
+static void
+teken_state_switch(teken_t *t, teken_state_t *s)
+{
+
+ t->t_nextstate = s;
+ t->t_curnum = 0;
+ t->t_stateflags |= TS_FIRSTDIGIT;
+}
+
+static int
+teken_state_numbers(teken_t *t, teken_char_t c)
+{
+
+ teken_assert(t->t_curnum < T_NUMSIZE);
+
+ if (c >= '0' && c <= '9') {
+ /*
+ * Don't do math with the default value of 1 when a
+ * custom number is inserted.
+ */
+ if (t->t_stateflags & TS_FIRSTDIGIT) {
+ t->t_stateflags &= ~TS_FIRSTDIGIT;
+ t->t_nums[t->t_curnum] = 0;
+ } else {
+ t->t_nums[t->t_curnum] *= 10;
+ }
+
+ t->t_nums[t->t_curnum] += c - '0';
+ return (1);
+ } else if (c == ';') {
+ if (t->t_stateflags & TS_FIRSTDIGIT)
+ t->t_nums[t->t_curnum] = 0;
+
+ /* Only allow a limited set of arguments. */
+ if (++t->t_curnum == T_NUMSIZE) {
+ teken_state_switch(t, teken_state_init);
+ return (1);
+ }
+
+ t->t_stateflags |= TS_FIRSTDIGIT;
+ return (1);
+ } else {
+ if (t->t_stateflags & TS_FIRSTDIGIT && t->t_curnum > 0) {
+ /* Finish off the last empty argument. */
+ t->t_nums[t->t_curnum] = 0;
+ t->t_curnum++;
+ } else if ((t->t_stateflags & TS_FIRSTDIGIT) == 0) {
+ /* Also count the last argument. */
+ t->t_curnum++;
+ }
+ }
+
+ return (0);
+}
+
+teken_color_t
+teken_256to8(teken_color_t c)
+{
+ unsigned int r, g, b;
+
+ if (c < 16) {
+ /* Traditional color indices. */
+ return (c % 8);
+ } else if (c >= 244) {
+ /* Upper grayscale colors. */
+ return (TC_WHITE);
+ } else if (c >= 232) {
+ /* Lower grayscale colors. */
+ return (TC_BLACK);
+ }
+
+ /* Convert to RGB. */
+ c -= 16;
+ b = c % 6;
+ g = (c / 6) % 6;
+ r = c / 36;
+
+ if (r < g) {
+ /* Possibly green. */
+ if (g < b)
+ return (TC_BLUE);
+ else if (g > b)
+ return (TC_GREEN);
+ else
+ return (TC_CYAN);
+ } else if (r > g) {
+ /* Possibly red. */
+ if (r < b)
+ return (TC_BLUE);
+ else if (r > b)
+ return (TC_RED);
+ else
+ return (TC_MAGENTA);
+ } else {
+ /* Possibly brown. */
+ if (g < b)
+ return (TC_BLUE);
+ else if (g > b)
+ return (TC_BROWN);
+ else if (r < 3)
+ return (TC_BLACK);
+ else
+ return (TC_WHITE);
+ }
+}
+
+static const char * const special_strings_cons25[] = {
+ [TKEY_UP] = "\x1B[A", [TKEY_DOWN] = "\x1B[B",
+ [TKEY_LEFT] = "\x1B[D", [TKEY_RIGHT] = "\x1B[C",
+
+ [TKEY_HOME] = "\x1B[H", [TKEY_END] = "\x1B[F",
+ [TKEY_INSERT] = "\x1B[L", [TKEY_DELETE] = "\x7F",
+ [TKEY_PAGE_UP] = "\x1B[I", [TKEY_PAGE_DOWN] = "\x1B[G",
+
+ [TKEY_F1] = "\x1B[M", [TKEY_F2] = "\x1B[N",
+ [TKEY_F3] = "\x1B[O", [TKEY_F4] = "\x1B[P",
+ [TKEY_F5] = "\x1B[Q", [TKEY_F6] = "\x1B[R",
+ [TKEY_F7] = "\x1B[S", [TKEY_F8] = "\x1B[T",
+ [TKEY_F9] = "\x1B[U", [TKEY_F10] = "\x1B[V",
+ [TKEY_F11] = "\x1B[W", [TKEY_F12] = "\x1B[X",
+};
+
+static const char * const special_strings_ckeys[] = {
+ [TKEY_UP] = "\x1BOA", [TKEY_DOWN] = "\x1BOB",
+ [TKEY_LEFT] = "\x1BOD", [TKEY_RIGHT] = "\x1BOC",
+
+ [TKEY_HOME] = "\x1BOH", [TKEY_END] = "\x1BOF",
+};
+
+static const char * const special_strings_normal[] = {
+ [TKEY_UP] = "\x1B[A", [TKEY_DOWN] = "\x1B[B",
+ [TKEY_LEFT] = "\x1B[D", [TKEY_RIGHT] = "\x1B[C",
+
+ [TKEY_HOME] = "\x1B[H", [TKEY_END] = "\x1B[F",
+ [TKEY_INSERT] = "\x1B[2~", [TKEY_DELETE] = "\x1B[3~",
+ [TKEY_PAGE_UP] = "\x1B[5~", [TKEY_PAGE_DOWN] = "\x1B[6~",
+
+ [TKEY_F1] = "\x1BOP", [TKEY_F2] = "\x1BOQ",
+ [TKEY_F3] = "\x1BOR", [TKEY_F4] = "\x1BOS",
+ [TKEY_F5] = "\x1B[15~", [TKEY_F6] = "\x1B[17~",
+ [TKEY_F7] = "\x1B[18~", [TKEY_F8] = "\x1B[19~",
+ [TKEY_F9] = "\x1B[20~", [TKEY_F10] = "\x1B[21~",
+ [TKEY_F11] = "\x1B[23~", [TKEY_F12] = "\x1B[24~",
+};
+
+const char *
+teken_get_sequence(teken_t *t, unsigned int k)
+{
+
+ /* Cons25 mode. */
+ if (t->t_stateflags & TS_CONS25 &&
+ k < sizeof special_strings_cons25 / sizeof(char *))
+ return (special_strings_cons25[k]);
+
+ /* Cursor keys mode. */
+ if (t->t_stateflags & TS_CURSORKEYS &&
+ k < sizeof special_strings_ckeys / sizeof(char *))
+ return (special_strings_ckeys[k]);
+
+ /* Default xterm sequences. */
+ if (k < sizeof special_strings_normal / sizeof(char *))
+ return (special_strings_normal[k]);
+
+ return (NULL);
+}
+
+#include "teken_state.h"
diff --git a/teken/teken.h b/teken/teken.h
new file mode 100644
index 0000000..e5c252b
--- /dev/null
+++ b/teken/teken.h
@@ -0,0 +1,223 @@
+/*-
+ * Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/sys/teken/teken.h 259667 2013-12-20 21:31:50Z ed $
+ */
+
+#ifndef _TEKEN_H_
+#define _TEKEN_H_
+
+// !!! Start of Mojo addition.
+#include <stdint.h>
+// !!! End of Mojo addition.
+#include <sys/types.h>
+
+/*
+ * libteken: terminal emulation library.
+ *
+ * This library converts an UTF-8 stream of bytes to terminal drawing
+ * commands.
+ */
+
+// !!! Start of Mojo addition.
+#ifdef __cplusplus
+extern "C" {
+#endif
+// !!! End of Mojo addition.
+
+typedef uint32_t teken_char_t;
+typedef unsigned short teken_unit_t;
+typedef unsigned char teken_format_t;
+#define TF_BOLD 0x01 /* Bold character. */
+#define TF_UNDERLINE 0x02 /* Underline character. */
+#define TF_BLINK 0x04 /* Blinking character. */
+#define TF_REVERSE 0x08 /* Reverse rendered character. */
+#define TF_CJK_RIGHT 0x10 /* Right-hand side of CJK character. */
+typedef unsigned char teken_color_t;
+#define TC_BLACK 0
+#define TC_RED 1
+#define TC_GREEN 2
+#define TC_BROWN 3
+#define TC_BLUE 4
+#define TC_MAGENTA 5
+#define TC_CYAN 6
+#define TC_WHITE 7
+#define TC_NCOLORS 8
+
+typedef struct {
+ teken_unit_t tp_row;
+ teken_unit_t tp_col;
+} teken_pos_t;
+typedef struct {
+ teken_pos_t tr_begin;
+ teken_pos_t tr_end;
+} teken_rect_t;
+typedef struct {
+ teken_format_t ta_format;
+ teken_color_t ta_fgcolor;
+ teken_color_t ta_bgcolor;
+} teken_attr_t;
+typedef struct {
+ teken_unit_t ts_begin;
+ teken_unit_t ts_end;
+} teken_span_t;
+
+typedef struct __teken teken_t;
+
+typedef void teken_state_t(teken_t *, teken_char_t);
+
+/*
+ * Drawing routines supplied by the user.
+ */
+
+typedef void tf_bell_t(void *);
+typedef void tf_cursor_t(void *, const teken_pos_t *);
+typedef void tf_putchar_t(void *, const teken_pos_t *, teken_char_t,
+ const teken_attr_t *);
+typedef void tf_fill_t(void *, const teken_rect_t *, teken_char_t,
+ const teken_attr_t *);
+typedef void tf_copy_t(void *, const teken_rect_t *, const teken_pos_t *);
+typedef void tf_param_t(void *, int, unsigned int);
+#define TP_SHOWCURSOR 0
+#define TP_KEYPADAPP 1
+#define TP_AUTOREPEAT 2
+#define TP_SWITCHVT 3
+#define TP_132COLS 4
+#define TP_SETBELLPD 5
+#define TP_SETBELLPD_PITCH(pd) ((pd) >> 16)
+#define TP_SETBELLPD_DURATION(pd) ((pd) & 0xffff)
+#define TP_MOUSE 6
+typedef void tf_respond_t(void *, const void *, size_t);
+
+typedef struct {
+ tf_bell_t *tf_bell;
+ tf_cursor_t *tf_cursor;
+ tf_putchar_t *tf_putchar;
+ tf_fill_t *tf_fill;
+ tf_copy_t *tf_copy;
+ tf_param_t *tf_param;
+ tf_respond_t *tf_respond;
+} teken_funcs_t;
+
+typedef teken_char_t teken_scs_t(teken_t *, teken_char_t);
+
+/*
+ * Terminal state.
+ */
+
+struct __teken {
+ const teken_funcs_t *t_funcs;
+ void *t_softc;
+
+ teken_state_t *t_nextstate;
+ unsigned int t_stateflags;
+
+#define T_NUMSIZE 8
+ unsigned int t_nums[T_NUMSIZE];
+ unsigned int t_curnum;
+
+ teken_pos_t t_cursor;
+ teken_attr_t t_curattr;
+ teken_pos_t t_saved_cursor;
+ teken_attr_t t_saved_curattr;
+
+ teken_attr_t t_defattr;
+ teken_pos_t t_winsize;
+
+ /* For DECSTBM. */
+ teken_span_t t_scrollreg;
+ /* For DECOM. */
+ teken_span_t t_originreg;
+
+#define T_NUMCOL 160
+ unsigned int t_tabstops[T_NUMCOL / (sizeof(unsigned int) * 8)];
+
+ unsigned int t_utf8_left;
+ teken_char_t t_utf8_partial;
+
+ unsigned int t_curscs;
+ teken_scs_t *t_saved_curscs;
+ teken_scs_t *t_scs[2];
+};
+
+/* Initialize teken structure. */
+void teken_init(teken_t *, const teken_funcs_t *, void *);
+
+/* Deliver character input. */
+void teken_input(teken_t *, const void *, size_t);
+
+/* Get/set teken attributes. */
+const teken_pos_t *teken_get_cursor(teken_t *);
+const teken_attr_t *teken_get_curattr(teken_t *);
+const teken_attr_t *teken_get_defattr(teken_t *);
+void teken_get_defattr_cons25(teken_t *, int *, int *);
+const teken_pos_t *teken_get_winsize(teken_t *);
+void teken_set_cursor(teken_t *, const teken_pos_t *);
+void teken_set_curattr(teken_t *, const teken_attr_t *);
+void teken_set_defattr(teken_t *, const teken_attr_t *);
+void teken_set_winsize(teken_t *, const teken_pos_t *);
+void teken_set_winsize_noreset(teken_t *, const teken_pos_t *);
+
+/* Key input escape sequences. */
+#define TKEY_UP 0x00
+#define TKEY_DOWN 0x01
+#define TKEY_LEFT 0x02
+#define TKEY_RIGHT 0x03
+
+#define TKEY_HOME 0x04
+#define TKEY_END 0x05
+#define TKEY_INSERT 0x06
+#define TKEY_DELETE 0x07
+#define TKEY_PAGE_UP 0x08
+#define TKEY_PAGE_DOWN 0x09
+
+#define TKEY_F1 0x0a
+#define TKEY_F2 0x0b
+#define TKEY_F3 0x0c
+#define TKEY_F4 0x0d
+#define TKEY_F5 0x0e
+#define TKEY_F6 0x0f
+#define TKEY_F7 0x10
+#define TKEY_F8 0x11
+#define TKEY_F9 0x12
+#define TKEY_F10 0x13
+#define TKEY_F11 0x14
+#define TKEY_F12 0x15
+const char *teken_get_sequence(teken_t *, unsigned int);
+
+/* Legacy features. */
+void teken_set_8bit(teken_t *);
+void teken_set_cons25(teken_t *);
+
+/* Color conversion. */
+teken_color_t teken_256to8(teken_color_t);
+
+// !!! Start of Mojo addition.
+#ifdef __cplusplus
+} // extern "C"
+#endif
+// !!! End of Mojo addition.
+
+#endif /* !_TEKEN_H_ */
diff --git a/teken/teken_scs.h b/teken/teken_scs.h
new file mode 100644
index 0000000..c055894
--- /dev/null
+++ b/teken/teken_scs.h
@@ -0,0 +1,80 @@
+/*-
+ * Copyright (c) 2009 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/sys/teken/teken_scs.h 203659 2010-02-08 09:16:59Z ed $
+ */
+
+static inline teken_char_t
+teken_scs_process(teken_t *t, teken_char_t c)
+{
+
+ return (t->t_scs[t->t_curscs](t, c));
+}
+
+/* Unicode points for VT100 box drawing. */
+static const uint16_t teken_boxdrawing_unicode[31] = {
+ 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
+ 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
+ 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
+ 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7
+};
+
+/* ASCII points for VT100 box drawing. */
+static const uint8_t teken_boxdrawing_8bit[31] = {
+ '?', '?', 'H', 'F', 'C', 'L', '?', '?',
+ 'N', 'V', '+', '+', '+', '+', '+', '-',
+ '-', '-', '-', '-', '+', '+', '+', '+',
+ '|', '?', '?', '?', '?', '?', '?',
+};
+
+static teken_char_t
+teken_scs_special_graphics(teken_t *t, teken_char_t c)
+{
+
+ /* Box drawing. */
+ if (c >= '`' && c <= '~')
+ return (t->t_stateflags & TS_8BIT ?
+ teken_boxdrawing_8bit[c - '`'] :
+ teken_boxdrawing_unicode[c - '`']);
+ return (c);
+}
+
+static teken_char_t
+teken_scs_uk_national(teken_t *t, teken_char_t c)
+{
+
+ /* Pound sign. */
+ if (c == '#')
+ return (t->t_stateflags & TS_8BIT ? 0x9c : 0xa3);
+ return (c);
+}
+
+static teken_char_t
+teken_scs_us_ascii(teken_t *t __unused, teken_char_t c)
+{
+
+ /* No processing. */
+ return (c);
+}
diff --git a/teken/teken_state.h b/teken/teken_state.h
new file mode 100644
index 0000000..65b0b44
--- /dev/null
+++ b/teken/teken_state.h
@@ -0,0 +1,383 @@
+/* Generated file. Do not edit. */
+
+static teken_state_t teken_state_2;
+static teken_state_t teken_state_6;
+static teken_state_t teken_state_1;
+static teken_state_t teken_state_7;
+static teken_state_t teken_state_8;
+static teken_state_t teken_state_3;
+static teken_state_t teken_state_5;
+static teken_state_t teken_state_4;
+
+/* '' */
+static void
+teken_state_init(teken_t *t, teken_char_t c)
+{
+
+ switch (c) {
+ case '\x1B':
+ teken_state_switch(t, teken_state_1);
+ return;
+ default:
+ teken_subr_regular_character(t, c);
+ break;
+ }
+}
+
+/* '^[[' */
+static void
+teken_state_2(teken_t *t, teken_char_t c)
+{
+
+ if (teken_state_numbers(t, c))
+ return;
+
+ switch (c) {
+ case 'X': /* ECH: Erase character */
+ teken_subr_erase_character(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case 'Z': /* CBT: Cursor Backward Tabulation */
+ teken_subr_cursor_backward_tabulation(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case '`': /* HPA: Horizontal Position Absolute */
+ teken_subr_horizontal_position_absolute(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case 'a': /* CUF: Cursor Forward */
+ teken_subr_cursor_forward(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case 'c': /* DA1: Primary Device Attributes */
+ teken_subr_primary_device_attributes(t, t->t_curnum < 1 ? 0 : t->t_nums[0]);
+ break;
+ case 'd': /* VPA: Vertical Position Absolute */
+ teken_subr_vertical_position_absolute(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case 'e': /* CUD: Cursor Down */
+ teken_subr_cursor_down(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case 'f': /* CUP: Cursor Position */
+ teken_subr_cursor_position(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0], (t->t_curnum < 2 || t->t_nums[1] == 0) ? 1 : t->t_nums[1]);
+ break;
+ case 'g': /* TBC: Tab Clear */
+ teken_subr_tab_clear(t, t->t_curnum < 1 ? 0 : t->t_nums[0]);
+ break;
+ case 'h': /* SM: Set Mode */
+ teken_subr_set_mode(t, t->t_curnum < 1 ? 0 : t->t_nums[0]);
+ break;
+ case 'l': /* RM: Reset Mode */
+ teken_subr_reset_mode(t, t->t_curnum < 1 ? 0 : t->t_nums[0]);
+ break;
+ case 'm': /* SGR: Set Graphic Rendition */
+ teken_subr_set_graphic_rendition(t, t->t_curnum, t->t_nums);
+ break;
+ case 'n': /* CPR: Cursor Position Report */
+ teken_subr_cursor_position_report(t, t->t_curnum < 1 ? 0 : t->t_nums[0]);
+ break;
+ case 'r': /* DECSTBM: Set top and bottom margins */
+ teken_subr_set_top_and_bottom_margins(t, t->t_curnum < 1 ? 0 : t->t_nums[0], t->t_curnum < 2 ? 0 : t->t_nums[1]);
+ break;
+ case 's': /* DECSC: Save cursor */
+ teken_subr_save_cursor(t);
+ break;
+ case 'u': /* DECRC: Restore cursor */
+ teken_subr_restore_cursor(t);
+ break;
+ case 'x': /* C25SGR: Cons25 set graphic rendition */
+ teken_subr_cons25_set_graphic_rendition(t, t->t_curnum < 1 ? 0 : t->t_nums[0], t->t_curnum < 2 ? 0 : t->t_nums[1]);
+ break;
+ case 'z': /* C25VTSW: Cons25 switch virtual terminal */
+ teken_subr_cons25_switch_virtual_terminal(t, t->t_curnum < 1 ? 0 : t->t_nums[0]);
+ break;
+ case '@': /* ICH: Insert character */
+ teken_subr_insert_character(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case 'A': /* CUU: Cursor Up */
+ teken_subr_cursor_up(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case 'B': /* CUD: Cursor Down */
+ teken_subr_cursor_down(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case 'C': /* CUF: Cursor Forward */
+ teken_subr_cursor_forward(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case 'D': /* CUB: Cursor Backward */
+ teken_subr_cursor_backward(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case 'E': /* CNL: Cursor Next Line */
+ teken_subr_cursor_next_line(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case 'F': /* CPL: Cursor Previous Line */
+ teken_subr_cursor_previous_line(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case 'G': /* HPA: Horizontal Position Absolute */
+ teken_subr_horizontal_position_absolute(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case 'H': /* CUP: Cursor Position */
+ teken_subr_cursor_position(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0], (t->t_curnum < 2 || t->t_nums[1] == 0) ? 1 : t->t_nums[1]);
+ break;
+ case 'I': /* CHT: Cursor Forward Tabulation */
+ teken_subr_cursor_forward_tabulation(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case 'J': /* ED: Erase display */
+ teken_subr_erase_display(t, t->t_curnum < 1 ? 0 : t->t_nums[0]);
+ break;
+ case 'K': /* EL: Erase line */
+ teken_subr_erase_line(t, t->t_curnum < 1 ? 0 : t->t_nums[0]);
+ break;
+ case 'L': /* IL: Insert line */
+ teken_subr_insert_line(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case 'M': /* DL: Delete line */
+ teken_subr_delete_line(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case 'P': /* DC: Delete character */
+ teken_subr_delete_character(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case 'S': /* SU: Pan Down */
+ teken_subr_pan_down(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case 'T': /* SD: Pan Up */
+ teken_subr_pan_up(t, (t->t_curnum < 1 || t->t_nums[0] == 0) ? 1 : t->t_nums[0]);
+ break;
+ case '=':
+ teken_state_switch(t, teken_state_8);
+ return;
+ case '>':
+ teken_state_switch(t, teken_state_3);
+ return;
+ case '?':
+ teken_state_switch(t, teken_state_5);
+ return;
+ default:
+ teken_printf("Unsupported sequence in teken_state_2: %u\n", (unsigned int)c);
+ break;
+ }
+
+ teken_state_switch(t, teken_state_init);
+}
+
+/* '^[(' */
+static void
+teken_state_6(teken_t *t, teken_char_t c)
+{
+
+ switch (c) {
+ case '0': /* G0SCS0: G0 SCS Special Graphics */
+ teken_subr_g0_scs_special_graphics(t);
+ break;
+ case '1': /* G0SCS1: G0 SCS US ASCII */
+ teken_subr_g0_scs_us_ascii(t);
+ break;
+ case '2': /* G0SCS2: G0 SCS Special Graphics */
+ teken_subr_g0_scs_special_graphics(t);
+ break;
+ case 'A': /* G0SCSA: G0 SCS UK National */
+ teken_subr_g0_scs_uk_national(t);
+ break;
+ case 'B': /* G0SCSB: G0 SCS US ASCII */
+ teken_subr_g0_scs_us_ascii(t);
+ break;
+ default:
+ teken_printf("Unsupported sequence in teken_state_6: %u\n", (unsigned int)c);
+ break;
+ }
+
+ teken_state_switch(t, teken_state_init);
+}
+
+/* '^[' */
+static void
+teken_state_1(teken_t *t, teken_char_t c)
+{
+
+ switch (c) {
+ case '7': /* DECSC: Save cursor */
+ teken_subr_save_cursor(t);
+ break;
+ case '8': /* DECRC: Restore cursor */
+ teken_subr_restore_cursor(t);
+ break;
+ case '=': /* DECKPAM: Keypad application mode */
+ teken_subr_keypad_application_mode(t);
+ break;
+ case '>': /* DECKPNM: Keypad numeric mode */
+ teken_subr_keypad_numeric_mode(t);
+ break;
+ case 'D': /* IND: Index */
+ teken_subr_index(t);
+ break;
+ case 'E': /* NEL: Next line */
+ teken_subr_next_line(t);
+ break;
+ case 'H': /* HTS: Horizontal Tab Set */
+ teken_subr_horizontal_tab_set(t);
+ break;
+ case 'M': /* RI: Reverse index */
+ teken_subr_reverse_index(t);
+ break;
+ case 'P': /* DCS: Device Control String */
+ teken_subr_device_control_string(t);
+ break;
+ case ']': /* OSC: Operating System Command */
+ teken_subr_operating_system_command(t);
+ break;
+ case 'c': /* RIS: Reset to Initial State */
+ teken_subr_reset_to_initial_state(t);
+ break;
+ case '\\': /* ST: String Terminator */
+ teken_subr_string_terminator(t);
+ break;
+ case '[':
+ teken_state_switch(t, teken_state_2);
+ return;
+ case '(':
+ teken_state_switch(t, teken_state_6);
+ return;
+ case ')':
+ teken_state_switch(t, teken_state_7);
+ return;
+ case '#':
+ teken_state_switch(t, teken_state_4);
+ return;
+ default:
+ teken_printf("Unsupported sequence in teken_state_1: %u\n", (unsigned int)c);
+ break;
+ }
+
+ teken_state_switch(t, teken_state_init);
+}
+
+/* '^[)' */
+static void
+teken_state_7(teken_t *t, teken_char_t c)
+{
+
+ switch (c) {
+ case '0': /* G1SCS0: G1 SCS Special Graphics */
+ teken_subr_g1_scs_special_graphics(t);
+ break;
+ case '1': /* G1SCS1: G1 SCS US ASCII */
+ teken_subr_g1_scs_us_ascii(t);
+ break;
+ case '2': /* G1SCS2: G1 SCS Special Graphics */
+ teken_subr_g1_scs_special_graphics(t);
+ break;
+ case 'A': /* G1SCSA: G1 SCS UK National */
+ teken_subr_g1_scs_uk_national(t);
+ break;
+ case 'B': /* G1SCSB: G1 SCS US ASCII */
+ teken_subr_g1_scs_us_ascii(t);
+ break;
+ default:
+ teken_printf("Unsupported sequence in teken_state_7: %u\n", (unsigned int)c);
+ break;
+ }
+
+ teken_state_switch(t, teken_state_init);
+}
+
+/* '^[[=' */
+static void
+teken_state_8(teken_t *t, teken_char_t c)
+{
+
+ if (teken_state_numbers(t, c))
+ return;
+
+ switch (c) {
+ case 'B': /* C25BLPD: Cons25 set bell pitch duration */
+ teken_subr_cons25_set_bell_pitch_duration(t, t->t_curnum < 1 ? 0 : t->t_nums[0], t->t_curnum < 2 ? 0 : t->t_nums[1]);
+ break;
+ case 'F': /* C25ADFG: Cons25 set adapter foreground */
+ teken_subr_cons25_set_adapter_foreground(t, t->t_curnum < 1 ? 0 : t->t_nums[0]);
+ break;
+ case 'G': /* C25ADBG: Cons25 set adapter background */
+ teken_subr_cons25_set_adapter_background(t, t->t_curnum < 1 ? 0 : t->t_nums[0]);
+ break;
+ case 'S': /* C25CURS: Cons25 set cursor type */
+ teken_subr_cons25_set_cursor_type(t, t->t_curnum < 1 ? 0 : t->t_nums[0]);
+ break;
+ case 'T': /* C25MODE: Cons25 set terminal mode */
+ teken_subr_cons25_set_terminal_mode(t, t->t_curnum < 1 ? 0 : t->t_nums[0]);
+ break;
+ default:
+ teken_printf("Unsupported sequence in teken_state_8: %u\n", (unsigned int)c);
+ break;
+ }
+
+ teken_state_switch(t, teken_state_init);
+}
+
+/* '^[[>' */
+static void
+teken_state_3(teken_t *t, teken_char_t c)
+{
+
+ if (teken_state_numbers(t, c))
+ return;
+
+ switch (c) {
+ case 'c': /* DA2: Secondary Device Attributes */
+ teken_subr_secondary_device_attributes(t, t->t_curnum < 1 ? 0 : t->t_nums[0]);
+ break;
+ default:
+ teken_printf("Unsupported sequence in teken_state_3: %u\n", (unsigned int)c);
+ break;
+ }
+
+ teken_state_switch(t, teken_state_init);
+}
+
+/* '^[[?' */
+static void
+teken_state_5(teken_t *t, teken_char_t c)
+{
+
+ if (teken_state_numbers(t, c))
+ return;
+
+ switch (c) {
+ case 'h': /* DECSM: Set DEC mode */
+ teken_subr_set_dec_mode(t, t->t_curnum < 1 ? 0 : t->t_nums[0]);
+ break;
+ case 'l': /* DECRM: Reset DEC mode */
+ teken_subr_reset_dec_mode(t, t->t_curnum < 1 ? 0 : t->t_nums[0]);
+ break;
+ case 'n': /* DSR: Device Status Report */
+ teken_subr_device_status_report(t, t->t_curnum < 1 ? 0 : t->t_nums[0]);
+ break;
+ default:
+ teken_printf("Unsupported sequence in teken_state_5: %u\n", (unsigned int)c);
+ break;
+ }
+
+ teken_state_switch(t, teken_state_init);
+}
+
+/* '^[#' */
+static void
+teken_state_4(teken_t *t, teken_char_t c)
+{
+
+ switch (c) {
+ case '3': /* DECDHL: Double Height Double Width Line Top */
+ teken_subr_double_height_double_width_line_top(t);
+ break;
+ case '4': /* DECDHL: Double Height Double Width Line Bottom */
+ teken_subr_double_height_double_width_line_bottom(t);
+ break;
+ case '5': /* DECSWL: Single Height Single Width Line */
+ teken_subr_single_height_single_width_line(t);
+ break;
+ case '6': /* DECDWL: Single Height Double Width Line */
+ teken_subr_single_height_double_width_line(t);
+ break;
+ case '8': /* DECALN: Alignment test */
+ teken_subr_alignment_test(t);
+ break;
+ default:
+ teken_printf("Unsupported sequence in teken_state_4: %u\n", (unsigned int)c);
+ break;
+ }
+
+ teken_state_switch(t, teken_state_init);
+}
diff --git a/teken/teken_subr.h b/teken/teken_subr.h
new file mode 100644
index 0000000..5dea10b
--- /dev/null
+++ b/teken/teken_subr.h
@@ -0,0 +1,1306 @@
+/*-
+ * Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/sys/teken/teken_subr.h 259761 2013-12-23 05:47:27Z ed $
+ */
+
+static void teken_subr_cursor_up(teken_t *, unsigned int);
+static void teken_subr_erase_line(teken_t *, unsigned int);
+static void teken_subr_regular_character(teken_t *, teken_char_t);
+static void teken_subr_reset_to_initial_state(teken_t *);
+static void teken_subr_save_cursor(teken_t *);
+
+static inline int
+teken_tab_isset(teken_t *t, unsigned int col)
+{
+ unsigned int b, o;
+
+ if (col >= T_NUMCOL)
+ return ((col % 8) == 0);
+
+ b = col / (sizeof(unsigned int) * 8);
+ o = col % (sizeof(unsigned int) * 8);
+
+ return (t->t_tabstops[b] & (1 << o));
+}
+
+static inline void
+teken_tab_clear(teken_t *t, unsigned int col)
+{
+ unsigned int b, o;
+
+ if (col >= T_NUMCOL)
+ return;
+
+ b = col / (sizeof(unsigned int) * 8);
+ o = col % (sizeof(unsigned int) * 8);
+
+ t->t_tabstops[b] &= ~(1 << o);
+}
+
+static inline void
+teken_tab_set(teken_t *t, unsigned int col)
+{
+ unsigned int b, o;
+
+ if (col >= T_NUMCOL)
+ return;
+
+ b = col / (sizeof(unsigned int) * 8);
+ o = col % (sizeof(unsigned int) * 8);
+
+ t->t_tabstops[b] |= 1 << o;
+}
+
+static void
+teken_tab_default(teken_t *t)
+{
+ unsigned int i;
+
+ memset(&t->t_tabstops, 0, T_NUMCOL / 8);
+
+ for (i = 8; i < T_NUMCOL; i += 8)
+ teken_tab_set(t, i);
+}
+
+static void
+teken_subr_do_scroll(teken_t *t, int amount)
+{
+ teken_rect_t tr;
+ teken_pos_t tp;
+
+ teken_assert(t->t_cursor.tp_row <= t->t_winsize.tp_row);
+ teken_assert(t->t_scrollreg.ts_end <= t->t_winsize.tp_row);
+ teken_assert(amount != 0);
+
+ /* Copy existing data 1 line up. */
+ if (amount > 0) {
+ /* Scroll down. */
+
+ /* Copy existing data up. */
+ if (t->t_scrollreg.ts_begin + amount < t->t_scrollreg.ts_end) {
+ tr.tr_begin.tp_row = t->t_scrollreg.ts_begin + amount;
+ tr.tr_begin.tp_col = 0;
+ tr.tr_end.tp_row = t->t_scrollreg.ts_end;
+ tr.tr_end.tp_col = t->t_winsize.tp_col;
+ tp.tp_row = t->t_scrollreg.ts_begin;
+ tp.tp_col = 0;
+ teken_funcs_copy(t, &tr, &tp);
+
+ tr.tr_begin.tp_row = t->t_scrollreg.ts_end - amount;
+ } else {
+ tr.tr_begin.tp_row = t->t_scrollreg.ts_begin;
+ }
+
+ /* Clear the last lines. */
+ tr.tr_begin.tp_col = 0;
+ tr.tr_end.tp_row = t->t_scrollreg.ts_end;
+ tr.tr_end.tp_col = t->t_winsize.tp_col;
+ teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
+ } else {
+ /* Scroll up. */
+ amount = -amount;
+
+ /* Copy existing data down. */
+ if (t->t_scrollreg.ts_begin + amount < t->t_scrollreg.ts_end) {
+ tr.tr_begin.tp_row = t->t_scrollreg.ts_begin;
+ tr.tr_begin.tp_col = 0;
+ tr.tr_end.tp_row = t->t_scrollreg.ts_end - amount;
+ tr.tr_end.tp_col = t->t_winsize.tp_col;
+ tp.tp_row = t->t_scrollreg.ts_begin + amount;
+ tp.tp_col = 0;
+ teken_funcs_copy(t, &tr, &tp);
+
+ tr.tr_end.tp_row = t->t_scrollreg.ts_begin + amount;
+ } else {
+ tr.tr_end.tp_row = t->t_scrollreg.ts_end;
+ }
+
+ /* Clear the first lines. */
+ tr.tr_begin.tp_row = t->t_scrollreg.ts_begin;
+ tr.tr_begin.tp_col = 0;
+ tr.tr_end.tp_col = t->t_winsize.tp_col;
+ teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
+ }
+}
+
+static ssize_t
+teken_subr_do_cpr(teken_t *t, unsigned int cmd, char response[16])
+{
+
+ switch (cmd) {
+ case 5: /* Operating status. */
+ strcpy(response, "0n");
+ return (2);
+ case 6: { /* Cursor position. */
+ int len;
+
+ len = snprintf(response, 16, "%u;%uR",
+ (t->t_cursor.tp_row - t->t_originreg.ts_begin) + 1,
+ t->t_cursor.tp_col + 1);
+
+ if (len >= 16)
+ return (-1);
+ return (len);
+ }
+ case 15: /* Printer status. */
+ strcpy(response, "13n");
+ return (3);
+ case 25: /* UDK status. */
+ strcpy(response, "20n");
+ return (3);
+ case 26: /* Keyboard status. */
+ strcpy(response, "27;1n");
+ return (5);
+ default:
+ teken_printf("Unknown DSR\n");
+ return (-1);
+ }
+}
+
+static void
+teken_subr_alignment_test(teken_t *t)
+{
+ teken_rect_t tr;
+
+ t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
+ t->t_scrollreg.ts_begin = 0;
+ t->t_scrollreg.ts_end = t->t_winsize.tp_row;
+ t->t_originreg = t->t_scrollreg;
+ t->t_stateflags &= ~(TS_WRAPPED|TS_ORIGIN);
+ teken_funcs_cursor(t);
+
+ tr.tr_begin.tp_row = 0;
+ tr.tr_begin.tp_col = 0;
+ tr.tr_end = t->t_winsize;
+ teken_funcs_fill(t, &tr, 'E', &t->t_defattr);
+}
+
+static void
+teken_subr_backspace(teken_t *t)
+{
+
+ if (t->t_stateflags & TS_CONS25) {
+ if (t->t_cursor.tp_col == 0) {
+ if (t->t_cursor.tp_row == t->t_originreg.ts_begin)
+ return;
+ t->t_cursor.tp_row--;
+ t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
+ } else {
+ t->t_cursor.tp_col--;
+ }
+ } else {
+ if (t->t_cursor.tp_col == 0)
+ return;
+
+ t->t_cursor.tp_col--;
+ t->t_stateflags &= ~TS_WRAPPED;
+ }
+
+ teken_funcs_cursor(t);
+}
+
+static void
+teken_subr_bell(teken_t *t)
+{
+
+ teken_funcs_bell(t);
+}
+
+static void
+teken_subr_carriage_return(teken_t *t)
+{
+
+ t->t_cursor.tp_col = 0;
+ t->t_stateflags &= ~TS_WRAPPED;
+ teken_funcs_cursor(t);
+}
+
+static void
+teken_subr_cursor_backward(teken_t *t, unsigned int ncols)
+{
+
+ if (ncols > t->t_cursor.tp_col)
+ t->t_cursor.tp_col = 0;
+ else
+ t->t_cursor.tp_col -= ncols;
+ t->t_stateflags &= ~TS_WRAPPED;
+ teken_funcs_cursor(t);
+}
+
+static void
+teken_subr_cursor_backward_tabulation(teken_t *t, unsigned int ntabs)
+{
+
+ do {
+ /* Stop when we've reached the beginning of the line. */
+ if (t->t_cursor.tp_col == 0)
+ break;
+
+ t->t_cursor.tp_col--;
+
+ /* Tab marker set. */
+ if (teken_tab_isset(t, t->t_cursor.tp_col))
+ ntabs--;
+ } while (ntabs > 0);
+
+ teken_funcs_cursor(t);
+}
+
+static void
+teken_subr_cursor_down(teken_t *t, unsigned int nrows)
+{
+
+ if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end)
+ t->t_cursor.tp_row = t->t_scrollreg.ts_end - 1;
+ else
+ t->t_cursor.tp_row += nrows;
+ t->t_stateflags &= ~TS_WRAPPED;
+ teken_funcs_cursor(t);
+}
+
+static void
+teken_subr_cursor_forward(teken_t *t, unsigned int ncols)
+{
+
+ if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col)
+ t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
+ else
+ t->t_cursor.tp_col += ncols;
+ t->t_stateflags &= ~TS_WRAPPED;
+ teken_funcs_cursor(t);
+}
+
+static void
+teken_subr_cursor_forward_tabulation(teken_t *t, unsigned int ntabs)
+{
+
+ do {
+ /* Stop when we've reached the end of the line. */
+ if (t->t_cursor.tp_col == t->t_winsize.tp_col - 1)
+ break;
+
+ t->t_cursor.tp_col++;
+
+ /* Tab marker set. */
+ if (teken_tab_isset(t, t->t_cursor.tp_col))
+ ntabs--;
+ } while (ntabs > 0);
+
+ teken_funcs_cursor(t);
+}
+
+static void
+teken_subr_cursor_next_line(teken_t *t, unsigned int ncols)
+{
+
+ t->t_cursor.tp_col = 0;
+ teken_subr_cursor_down(t, ncols);
+}
+
+static void
+teken_subr_cursor_position(teken_t *t, unsigned int row, unsigned int col)
+{
+
+ t->t_cursor.tp_row = t->t_originreg.ts_begin + row - 1;
+ if (t->t_cursor.tp_row >= t->t_originreg.ts_end)
+ t->t_cursor.tp_row = t->t_originreg.ts_end - 1;
+
+ t->t_cursor.tp_col = col - 1;
+ if (t->t_cursor.tp_col >= t->t_winsize.tp_col)
+ t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
+
+ t->t_stateflags &= ~TS_WRAPPED;
+ teken_funcs_cursor(t);
+}
+
+static void
+teken_subr_cursor_position_report(teken_t *t, unsigned int cmd)
+{
+ char response[18] = "\x1B[";
+ ssize_t len;
+
+ len = teken_subr_do_cpr(t, cmd, response + 2);
+ if (len < 0)
+ return;
+
+ teken_funcs_respond(t, response, len + 2);
+}
+
+static void
+teken_subr_cursor_previous_line(teken_t *t, unsigned int ncols)
+{
+
+ t->t_cursor.tp_col = 0;
+ teken_subr_cursor_up(t, ncols);
+}
+
+static void
+teken_subr_cursor_up(teken_t *t, unsigned int nrows)
+{
+
+ if (t->t_scrollreg.ts_begin + nrows >= t->t_cursor.tp_row)
+ t->t_cursor.tp_row = t->t_scrollreg.ts_begin;
+ else
+ t->t_cursor.tp_row -= nrows;
+ t->t_stateflags &= ~TS_WRAPPED;
+ teken_funcs_cursor(t);
+}
+
+static void
+teken_subr_delete_character(teken_t *t, unsigned int ncols)
+{
+ teken_rect_t tr;
+
+ tr.tr_begin.tp_row = t->t_cursor.tp_row;
+ tr.tr_end.tp_row = t->t_cursor.tp_row + 1;
+ tr.tr_end.tp_col = t->t_winsize.tp_col;
+
+ if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) {
+ tr.tr_begin.tp_col = t->t_cursor.tp_col;
+ } else {
+ /* Copy characters to the left. */
+ tr.tr_begin.tp_col = t->t_cursor.tp_col + ncols;
+ teken_funcs_copy(t, &tr, &t->t_cursor);
+
+ tr.tr_begin.tp_col = t->t_winsize.tp_col - ncols;
+ }
+
+ /* Blank trailing columns. */
+ teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
+}
+
+static void
+teken_subr_delete_line(teken_t *t, unsigned int nrows)
+{
+ teken_rect_t tr;
+
+ /* Ignore if outside scrolling region. */
+ if (t->t_cursor.tp_row < t->t_scrollreg.ts_begin ||
+ t->t_cursor.tp_row >= t->t_scrollreg.ts_end)
+ return;
+
+ tr.tr_begin.tp_col = 0;
+ tr.tr_end.tp_row = t->t_scrollreg.ts_end;
+ tr.tr_end.tp_col = t->t_winsize.tp_col;
+
+ if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end) {
+ tr.tr_begin.tp_row = t->t_cursor.tp_row;
+ } else {
+ teken_pos_t tp;
+
+ /* Copy rows up. */
+ tr.tr_begin.tp_row = t->t_cursor.tp_row + nrows;
+ tp.tp_row = t->t_cursor.tp_row;
+ tp.tp_col = 0;
+ teken_funcs_copy(t, &tr, &tp);
+
+ tr.tr_begin.tp_row = t->t_scrollreg.ts_end - nrows;
+ }
+
+ /* Blank trailing rows. */
+ teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
+}
+
+static void
+teken_subr_device_control_string(teken_t *t)
+{
+
+ teken_printf("Unsupported device control string\n");
+ t->t_stateflags |= TS_INSTRING;
+}
+
+static void
+teken_subr_device_status_report(teken_t *t, unsigned int cmd)
+{
+ char response[19] = "\x1B[?";
+ ssize_t len;
+
+ len = teken_subr_do_cpr(t, cmd, response + 3);
+ if (len < 0)
+ return;
+
+ teken_funcs_respond(t, response, len + 3);
+}
+
+static void
+teken_subr_double_height_double_width_line_top(teken_t *t __unused)
+{
+
+ teken_printf("double height double width top\n");
+}
+
+static void
+teken_subr_double_height_double_width_line_bottom(teken_t *t __unused)
+{
+
+ teken_printf("double height double width bottom\n");
+}
+
+static void
+teken_subr_erase_character(teken_t *t, unsigned int ncols)
+{
+ teken_rect_t tr;
+
+ tr.tr_begin = t->t_cursor;
+ tr.tr_end.tp_row = t->t_cursor.tp_row + 1;
+
+ if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col)
+ tr.tr_end.tp_col = t->t_winsize.tp_col;
+ else
+ tr.tr_end.tp_col = t->t_cursor.tp_col + ncols;
+
+ teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
+}
+
+static void
+teken_subr_erase_display(teken_t *t, unsigned int mode)
+{
+ teken_rect_t r;
+
+ r.tr_begin.tp_col = 0;
+ r.tr_end.tp_col = t->t_winsize.tp_col;
+
+ switch (mode) {
+ case 1: /* Erase from the top to the cursor. */
+ teken_subr_erase_line(t, 1);
+
+ /* Erase lines above. */
+ if (t->t_cursor.tp_row == 0)
+ return;
+ r.tr_begin.tp_row = 0;
+ r.tr_end.tp_row = t->t_cursor.tp_row;
+ break;
+ case 2: /* Erase entire display. */
+ r.tr_begin.tp_row = 0;
+ r.tr_end.tp_row = t->t_winsize.tp_row;
+ break;
+ default: /* Erase from cursor to the bottom. */
+ teken_subr_erase_line(t, 0);
+
+ /* Erase lines below. */
+ if (t->t_cursor.tp_row == t->t_winsize.tp_row - 1)
+ return;
+ r.tr_begin.tp_row = t->t_cursor.tp_row + 1;
+ r.tr_end.tp_row = t->t_winsize.tp_row;
+ break;
+ }
+
+ teken_funcs_fill(t, &r, BLANK, &t->t_curattr);
+}
+
+static void
+teken_subr_erase_line(teken_t *t, unsigned int mode)
+{
+ teken_rect_t r;
+
+ r.tr_begin.tp_row = t->t_cursor.tp_row;
+ r.tr_end.tp_row = t->t_cursor.tp_row + 1;
+
+ switch (mode) {
+ case 1: /* Erase from the beginning of the line to the cursor. */
+ r.tr_begin.tp_col = 0;
+ r.tr_end.tp_col = t->t_cursor.tp_col + 1;
+ break;
+ case 2: /* Erase entire line. */
+ r.tr_begin.tp_col = 0;
+ r.tr_end.tp_col = t->t_winsize.tp_col;
+ break;
+ default: /* Erase from cursor to the end of the line. */
+ r.tr_begin.tp_col = t->t_cursor.tp_col;
+ r.tr_end.tp_col = t->t_winsize.tp_col;
+ break;
+ }
+
+ teken_funcs_fill(t, &r, BLANK, &t->t_curattr);
+}
+
+static void
+teken_subr_g0_scs_special_graphics(teken_t *t __unused)
+{
+
+ t->t_scs[0] = teken_scs_special_graphics;
+}
+
+static void
+teken_subr_g0_scs_uk_national(teken_t *t __unused)
+{
+
+ t->t_scs[0] = teken_scs_uk_national;
+}
+
+static void
+teken_subr_g0_scs_us_ascii(teken_t *t __unused)
+{
+
+ t->t_scs[0] = teken_scs_us_ascii;
+}
+
+static void
+teken_subr_g1_scs_special_graphics(teken_t *t __unused)
+{
+
+ t->t_scs[1] = teken_scs_special_graphics;
+}
+
+static void
+teken_subr_g1_scs_uk_national(teken_t *t __unused)
+{
+
+ t->t_scs[1] = teken_scs_uk_national;
+}
+
+static void
+teken_subr_g1_scs_us_ascii(teken_t *t __unused)
+{
+
+ t->t_scs[1] = teken_scs_us_ascii;
+}
+
+static void
+teken_subr_horizontal_position_absolute(teken_t *t, unsigned int col)
+{
+
+ t->t_cursor.tp_col = col - 1;
+ if (t->t_cursor.tp_col >= t->t_winsize.tp_col)
+ t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
+
+ t->t_stateflags &= ~TS_WRAPPED;
+ teken_funcs_cursor(t);
+}
+
+static void
+teken_subr_horizontal_tab(teken_t *t)
+{
+
+ teken_subr_cursor_forward_tabulation(t, 1);
+}
+
+static void
+teken_subr_horizontal_tab_set(teken_t *t)
+{
+
+ teken_tab_set(t, t->t_cursor.tp_col);
+}
+
+static void
+teken_subr_index(teken_t *t)
+{
+
+ if (t->t_cursor.tp_row < t->t_scrollreg.ts_end - 1) {
+ t->t_cursor.tp_row++;
+ t->t_stateflags &= ~TS_WRAPPED;
+ teken_funcs_cursor(t);
+ } else {
+ teken_subr_do_scroll(t, 1);
+ }
+}
+
+static void
+teken_subr_insert_character(teken_t *t, unsigned int ncols)
+{
+ teken_rect_t tr;
+
+ tr.tr_begin = t->t_cursor;
+ tr.tr_end.tp_row = t->t_cursor.tp_row + 1;
+
+ if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) {
+ tr.tr_end.tp_col = t->t_winsize.tp_col;
+ } else {
+ teken_pos_t tp;
+
+ /* Copy characters to the right. */
+ tr.tr_end.tp_col = t->t_winsize.tp_col - ncols;
+ tp.tp_row = t->t_cursor.tp_row;
+ tp.tp_col = t->t_cursor.tp_col + ncols;
+ teken_funcs_copy(t, &tr, &tp);
+
+ tr.tr_end.tp_col = t->t_cursor.tp_col + ncols;
+ }
+
+ /* Blank current location. */
+ teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
+}
+
+static void
+teken_subr_insert_line(teken_t *t, unsigned int nrows)
+{
+ teken_rect_t tr;
+
+ /* Ignore if outside scrolling region. */
+ if (t->t_cursor.tp_row < t->t_scrollreg.ts_begin ||
+ t->t_cursor.tp_row >= t->t_scrollreg.ts_end)
+ return;
+
+ tr.tr_begin.tp_row = t->t_cursor.tp_row;
+ tr.tr_begin.tp_col = 0;
+ tr.tr_end.tp_col = t->t_winsize.tp_col;
+
+ if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end) {
+ tr.tr_end.tp_row = t->t_scrollreg.ts_end;
+ } else {
+ teken_pos_t tp;
+
+ /* Copy lines down. */
+ tr.tr_end.tp_row = t->t_scrollreg.ts_end - nrows;
+ tp.tp_row = t->t_cursor.tp_row + nrows;
+ tp.tp_col = 0;
+ teken_funcs_copy(t, &tr, &tp);
+
+ tr.tr_end.tp_row = t->t_cursor.tp_row + nrows;
+ }
+
+ /* Blank current location. */
+ teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
+}
+
+static void
+teken_subr_keypad_application_mode(teken_t *t)
+{
+
+ teken_funcs_param(t, TP_KEYPADAPP, 1);
+}
+
+static void
+teken_subr_keypad_numeric_mode(teken_t *t)
+{
+
+ teken_funcs_param(t, TP_KEYPADAPP, 0);
+}
+
+static void
+teken_subr_newline(teken_t *t)
+{
+
+ t->t_cursor.tp_row++;
+
+ if (t->t_cursor.tp_row >= t->t_scrollreg.ts_end) {
+ teken_subr_do_scroll(t, 1);
+ t->t_cursor.tp_row = t->t_scrollreg.ts_end - 1;
+ }
+
+ t->t_stateflags &= ~TS_WRAPPED;
+ teken_funcs_cursor(t);
+}
+
+static void
+teken_subr_newpage(teken_t *t)
+{
+
+ if (t->t_stateflags & TS_CONS25) {
+ teken_rect_t tr;
+
+ /* Clear screen. */
+ tr.tr_begin.tp_row = t->t_originreg.ts_begin;
+ tr.tr_begin.tp_col = 0;
+ tr.tr_end.tp_row = t->t_originreg.ts_end;
+ tr.tr_end.tp_col = t->t_winsize.tp_col;
+ teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
+
+ /* Cursor at top left. */
+ t->t_cursor.tp_row = t->t_originreg.ts_begin;
+ t->t_cursor.tp_col = 0;
+ t->t_stateflags &= ~TS_WRAPPED;
+ teken_funcs_cursor(t);
+ } else {
+ teken_subr_newline(t);
+ }
+}
+
+static void
+teken_subr_next_line(teken_t *t)
+{
+
+ t->t_cursor.tp_col = 0;
+ teken_subr_newline(t);
+}
+
+static void
+teken_subr_operating_system_command(teken_t *t)
+{
+
+ teken_printf("Unsupported operating system command\n");
+ t->t_stateflags |= TS_INSTRING;
+}
+
+static void
+teken_subr_pan_down(teken_t *t, unsigned int nrows)
+{
+
+ teken_subr_do_scroll(t, (int)nrows);
+}
+
+static void
+teken_subr_pan_up(teken_t *t, unsigned int nrows)
+{
+
+ teken_subr_do_scroll(t, -(int)nrows);
+}
+
+static void
+teken_subr_primary_device_attributes(teken_t *t, unsigned int request)
+{
+
+ if (request == 0) {
+ const char response[] = "\x1B[?1;2c";
+
+ teken_funcs_respond(t, response, sizeof response - 1);
+ } else {
+ teken_printf("Unknown DA1\n");
+ }
+}
+
+static void
+teken_subr_do_putchar(teken_t *t, const teken_pos_t *tp, teken_char_t c,
+ int width)
+{
+
+ if (t->t_stateflags & TS_INSERT &&
+ tp->tp_col < t->t_winsize.tp_col - width) {
+ teken_rect_t ctr;
+ teken_pos_t ctp;
+
+ /* Insert mode. Move existing characters to the right. */
+ ctr.tr_begin = *tp;
+ ctr.tr_end.tp_row = tp->tp_row + 1;
+ ctr.tr_end.tp_col = t->t_winsize.tp_col - width;
+ ctp.tp_row = tp->tp_row;
+ ctp.tp_col = tp->tp_col + width;
+ teken_funcs_copy(t, &ctr, &ctp);
+ }
+
+ teken_funcs_putchar(t, tp, c, &t->t_curattr);
+
+ if (width == 2 && tp->tp_col + 1 < t->t_winsize.tp_col) {
+ teken_pos_t tp2;
+ teken_attr_t attr;
+
+ /* Print second half of CJK fullwidth character. */
+ tp2.tp_row = tp->tp_row;
+ tp2.tp_col = tp->tp_col + 1;
+ attr = t->t_curattr;
+ attr.ta_format |= TF_CJK_RIGHT;
+ teken_funcs_putchar(t, &tp2, c, &attr);
+ }
+}
+
+static void
+teken_subr_regular_character(teken_t *t, teken_char_t c)
+{
+ int width;
+
+ if (t->t_stateflags & TS_8BIT) {
+ if (!(t->t_stateflags & TS_CONS25) && (c <= 0x1b || c == 0x7f))
+ return;
+ c = teken_scs_process(t, c);
+ width = 1;
+ } else {
+ c = teken_scs_process(t, c);
+ width = teken_wcwidth(c);
+ /* XXX: Don't process zero-width characters yet. */
+ if (width <= 0)
+ return;
+ }
+
+ if (t->t_stateflags & TS_CONS25) {
+ teken_subr_do_putchar(t, &t->t_cursor, c, width);
+ t->t_cursor.tp_col += width;
+
+ if (t->t_cursor.tp_col >= t->t_winsize.tp_col) {
+ if (t->t_cursor.tp_row == t->t_scrollreg.ts_end - 1) {
+ /* Perform scrolling. */
+ teken_subr_do_scroll(t, 1);
+ } else {
+ /* No scrolling needed. */
+ if (t->t_cursor.tp_row <
+ t->t_winsize.tp_row - 1)
+ t->t_cursor.tp_row++;
+ }
+ t->t_cursor.tp_col = 0;
+ }
+ } else if (t->t_stateflags & TS_AUTOWRAP &&
+ ((t->t_stateflags & TS_WRAPPED &&
+ t->t_cursor.tp_col + 1 == t->t_winsize.tp_col) ||
+ t->t_cursor.tp_col + width > t->t_winsize.tp_col)) {
+ teken_pos_t tp;
+
+ /*
+ * Perform line wrapping, if:
+ * - Autowrapping is enabled, and
+ * - We're in the wrapped state at the last column, or
+ * - The character to be printed does not fit anymore.
+ */
+ if (t->t_cursor.tp_row == t->t_scrollreg.ts_end - 1) {
+ /* Perform scrolling. */
+ teken_subr_do_scroll(t, 1);
+ tp.tp_row = t->t_scrollreg.ts_end - 1;
+ } else {
+ /* No scrolling needed. */
+ tp.tp_row = t->t_cursor.tp_row + 1;
+ if (tp.tp_row == t->t_winsize.tp_row) {
+ /*
+ * Corner case: regular character
+ * outside scrolling region, but at the
+ * bottom of the screen.
+ */
+ teken_subr_do_putchar(t, &t->t_cursor,
+ c, width);
+ return;
+ }
+ }
+
+ tp.tp_col = 0;
+ teken_subr_do_putchar(t, &tp, c, width);
+
+ t->t_cursor.tp_row = tp.tp_row;
+ t->t_cursor.tp_col = width;
+ t->t_stateflags &= ~TS_WRAPPED;
+ } else {
+ /* No line wrapping needed. */
+ teken_subr_do_putchar(t, &t->t_cursor, c, width);
+ t->t_cursor.tp_col += width;
+
+ if (t->t_cursor.tp_col >= t->t_winsize.tp_col) {
+ t->t_stateflags |= TS_WRAPPED;
+ t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
+ } else {
+ t->t_stateflags &= ~TS_WRAPPED;
+ }
+ }
+
+ teken_funcs_cursor(t);
+}
+
+static void
+teken_subr_reset_dec_mode(teken_t *t, unsigned int cmd)
+{
+
+ switch (cmd) {
+ case 1: /* Cursor keys mode. */
+ t->t_stateflags &= ~TS_CURSORKEYS;
+ break;
+ case 2: /* DECANM: ANSI/VT52 mode. */
+ teken_printf("DECRST VT52\n");
+ break;
+ case 3: /* 132 column mode. */
+ teken_funcs_param(t, TP_132COLS, 0);
+ teken_subr_reset_to_initial_state(t);
+ break;
+ case 5: /* Inverse video. */
+ teken_printf("DECRST inverse video\n");
+ break;
+ case 6: /* Origin mode. */
+ t->t_stateflags &= ~TS_ORIGIN;
+ t->t_originreg.ts_begin = 0;
+ t->t_originreg.ts_end = t->t_winsize.tp_row;
+ t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
+ t->t_stateflags &= ~TS_WRAPPED;
+ teken_funcs_cursor(t);
+ break;
+ case 7: /* Autowrap mode. */
+ t->t_stateflags &= ~TS_AUTOWRAP;
+ break;
+ case 8: /* Autorepeat mode. */
+ teken_funcs_param(t, TP_AUTOREPEAT, 0);
+ break;
+ case 25: /* Hide cursor. */
+ teken_funcs_param(t, TP_SHOWCURSOR, 0);
+ break;
+ case 40: /* Disallow 132 columns. */
+ teken_printf("DECRST allow 132\n");
+ break;
+ case 45: /* Disable reverse wraparound. */
+ teken_printf("DECRST reverse wraparound\n");
+ break;
+ case 47: /* Switch to alternate buffer. */
+ teken_printf("Switch to alternate buffer\n");
+ break;
+ case 1000: /* Mouse input. */
+ teken_funcs_param(t, TP_MOUSE, 0);
+ break;
+ default:
+ teken_printf("Unknown DECRST: %u\n", cmd);
+ }
+}
+
+static void
+teken_subr_reset_mode(teken_t *t, unsigned int cmd)
+{
+
+ switch (cmd) {
+ case 4:
+ t->t_stateflags &= ~TS_INSERT;
+ break;
+ default:
+ teken_printf("Unknown reset mode: %u\n", cmd);
+ }
+}
+
+static void
+teken_subr_do_resize(teken_t *t)
+{
+
+ t->t_scrollreg.ts_begin = 0;
+ t->t_scrollreg.ts_end = t->t_winsize.tp_row;
+ t->t_originreg = t->t_scrollreg;
+}
+
+static void
+teken_subr_do_reset(teken_t *t)
+{
+
+ t->t_curattr = t->t_defattr;
+ t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
+ t->t_scrollreg.ts_begin = 0;
+ t->t_scrollreg.ts_end = t->t_winsize.tp_row;
+ t->t_originreg = t->t_scrollreg;
+ t->t_stateflags &= TS_8BIT|TS_CONS25;
+ t->t_stateflags |= TS_AUTOWRAP;
+
+ t->t_scs[0] = teken_scs_us_ascii;
+ t->t_scs[1] = teken_scs_us_ascii;
+ t->t_curscs = 0;
+
+ teken_subr_save_cursor(t);
+ teken_tab_default(t);
+}
+
+static void
+teken_subr_reset_to_initial_state(teken_t *t)
+{
+
+ teken_subr_do_reset(t);
+ teken_subr_erase_display(t, 2);
+ teken_funcs_param(t, TP_SHOWCURSOR, 1);
+ teken_funcs_cursor(t);
+}
+
+static void
+teken_subr_restore_cursor(teken_t *t)
+{
+
+ t->t_cursor = t->t_saved_cursor;
+ t->t_curattr = t->t_saved_curattr;
+ t->t_scs[t->t_curscs] = t->t_saved_curscs;
+ t->t_stateflags &= ~TS_WRAPPED;
+
+ /* Get out of origin mode when the cursor is moved outside. */
+ if (t->t_cursor.tp_row < t->t_originreg.ts_begin ||
+ t->t_cursor.tp_row >= t->t_originreg.ts_end) {
+ t->t_stateflags &= ~TS_ORIGIN;
+ t->t_originreg.ts_begin = 0;
+ t->t_originreg.ts_end = t->t_winsize.tp_row;
+ }
+
+ teken_funcs_cursor(t);
+}
+
+static void
+teken_subr_reverse_index(teken_t *t)
+{
+
+ if (t->t_cursor.tp_row > t->t_scrollreg.ts_begin) {
+ t->t_cursor.tp_row--;
+ t->t_stateflags &= ~TS_WRAPPED;
+ teken_funcs_cursor(t);
+ } else {
+ teken_subr_do_scroll(t, -1);
+ }
+}
+
+static void
+teken_subr_save_cursor(teken_t *t)
+{
+
+ t->t_saved_cursor = t->t_cursor;
+ t->t_saved_curattr = t->t_curattr;
+ t->t_saved_curscs = t->t_scs[t->t_curscs];
+}
+
+static void
+teken_subr_secondary_device_attributes(teken_t *t, unsigned int request)
+{
+
+ if (request == 0) {
+ const char response[] = "\x1B[>0;10;0c";
+ teken_funcs_respond(t, response, sizeof response - 1);
+ } else {
+ teken_printf("Unknown DA2\n");
+ }
+}
+
+static void
+teken_subr_set_dec_mode(teken_t *t, unsigned int cmd)
+{
+
+ switch (cmd) {
+ case 1: /* Cursor keys mode. */
+ t->t_stateflags |= TS_CURSORKEYS;
+ break;
+ case 2: /* DECANM: ANSI/VT52 mode. */
+ teken_printf("DECSET VT52\n");
+ break;
+ case 3: /* 132 column mode. */
+ teken_funcs_param(t, TP_132COLS, 1);
+ teken_subr_reset_to_initial_state(t);
+ break;
+ case 5: /* Inverse video. */
+ teken_printf("DECSET inverse video\n");
+ break;
+ case 6: /* Origin mode. */
+ t->t_stateflags |= TS_ORIGIN;
+ t->t_originreg = t->t_scrollreg;
+ t->t_cursor.tp_row = t->t_scrollreg.ts_begin;
+ t->t_cursor.tp_col = 0;
+ t->t_stateflags &= ~TS_WRAPPED;
+ teken_funcs_cursor(t);
+ break;
+ case 7: /* Autowrap mode. */
+ t->t_stateflags |= TS_AUTOWRAP;
+ break;
+ case 8: /* Autorepeat mode. */
+ teken_funcs_param(t, TP_AUTOREPEAT, 1);
+ break;
+ case 25: /* Display cursor. */
+ teken_funcs_param(t, TP_SHOWCURSOR, 1);
+ break;
+ case 40: /* Allow 132 columns. */
+ teken_printf("DECSET allow 132\n");
+ break;
+ case 45: /* Enable reverse wraparound. */
+ teken_printf("DECSET reverse wraparound\n");
+ break;
+ case 47: /* Switch to alternate buffer. */
+ teken_printf("Switch away from alternate buffer\n");
+ break;
+ case 1000: /* Mouse input. */
+ teken_funcs_param(t, TP_MOUSE, 1);
+ break;
+ default:
+ teken_printf("Unknown DECSET: %u\n", cmd);
+ }
+}
+
+static void
+teken_subr_set_mode(teken_t *t, unsigned int cmd)
+{
+
+ switch (cmd) {
+ case 4:
+ teken_printf("Insert mode\n");
+ t->t_stateflags |= TS_INSERT;
+ break;
+ default:
+ teken_printf("Unknown set mode: %u\n", cmd);
+ }
+}
+
+static void
+teken_subr_set_graphic_rendition(teken_t *t, unsigned int ncmds,
+ unsigned int cmds[])
+{
+ unsigned int i, n;
+
+ /* No attributes means reset. */
+ if (ncmds == 0) {
+ t->t_curattr = t->t_defattr;
+ return;
+ }
+
+ for (i = 0; i < ncmds; i++) {
+ n = cmds[i];
+
+ switch (n) {
+ case 0: /* Reset. */
+ t->t_curattr = t->t_defattr;
+ break;
+ case 1: /* Bold. */
+ t->t_curattr.ta_format |= TF_BOLD;
+ break;
+ case 4: /* Underline. */
+ t->t_curattr.ta_format |= TF_UNDERLINE;
+ break;
+ case 5: /* Blink. */
+ t->t_curattr.ta_format |= TF_BLINK;
+ break;
+ case 7: /* Reverse. */
+ t->t_curattr.ta_format |= TF_REVERSE;
+ break;
+ case 22: /* Remove bold. */
+ t->t_curattr.ta_format &= ~TF_BOLD;
+ break;
+ case 24: /* Remove underline. */
+ t->t_curattr.ta_format &= ~TF_UNDERLINE;
+ break;
+ case 25: /* Remove blink. */
+ t->t_curattr.ta_format &= ~TF_BLINK;
+ break;
+ case 27: /* Remove reverse. */
+ t->t_curattr.ta_format &= ~TF_REVERSE;
+ break;
+ case 30: /* Set foreground color: black */
+ case 31: /* Set foreground color: red */
+ case 32: /* Set foreground color: green */
+ case 33: /* Set foreground color: brown */
+ case 34: /* Set foreground color: blue */
+ case 35: /* Set foreground color: magenta */
+ case 36: /* Set foreground color: cyan */
+ case 37: /* Set foreground color: white */
+ t->t_curattr.ta_fgcolor = n - 30;
+ break;
+ case 38: /* Set foreground color: 256 color mode */
+ if (i + 2 >= ncmds || cmds[i + 1] != 5)
+ continue;
+ t->t_curattr.ta_fgcolor = cmds[i + 2];
+ i += 2;
+ break;
+ case 39: /* Set default foreground color. */
+ t->t_curattr.ta_fgcolor = t->t_defattr.ta_fgcolor;
+ break;
+ case 40: /* Set background color: black */
+ case 41: /* Set background color: red */
+ case 42: /* Set background color: green */
+ case 43: /* Set background color: brown */
+ case 44: /* Set background color: blue */
+ case 45: /* Set background color: magenta */
+ case 46: /* Set background color: cyan */
+ case 47: /* Set background color: white */
+ t->t_curattr.ta_bgcolor = n - 40;
+ break;
+ case 48: /* Set background color: 256 color mode */
+ if (i + 2 >= ncmds || cmds[i + 1] != 5)
+ continue;
+ t->t_curattr.ta_bgcolor = cmds[i + 2];
+ i += 2;
+ break;
+ case 49: /* Set default background color. */
+ t->t_curattr.ta_bgcolor = t->t_defattr.ta_bgcolor;
+ break;
+ case 90: /* Set bright foreground color: black */
+ case 91: /* Set bright foreground color: red */
+ case 92: /* Set bright foreground color: green */
+ case 93: /* Set bright foreground color: brown */
+ case 94: /* Set bright foreground color: blue */
+ case 95: /* Set bright foreground color: magenta */
+ case 96: /* Set bright foreground color: cyan */
+ case 97: /* Set bright foreground color: white */
+ t->t_curattr.ta_fgcolor = n - 90 + 8;
+ break;
+ case 100: /* Set bright background color: black */
+ case 101: /* Set bright background color: red */
+ case 102: /* Set bright background color: green */
+ case 103: /* Set bright background color: brown */
+ case 104: /* Set bright background color: blue */
+ case 105: /* Set bright background color: magenta */
+ case 106: /* Set bright background color: cyan */
+ case 107: /* Set bright background color: white */
+ t->t_curattr.ta_bgcolor = n - 100 + 8;
+ break;
+ default:
+ teken_printf("unsupported attribute %u\n", n);
+ }
+ }
+}
+
+static void
+teken_subr_set_top_and_bottom_margins(teken_t *t, unsigned int top,
+ unsigned int bottom)
+{
+
+ /* Adjust top row number. */
+ if (top > 0)
+ top--;
+ /* Adjust bottom row number. */
+ if (bottom == 0 || bottom > t->t_winsize.tp_row)
+ bottom = t->t_winsize.tp_row;
+
+ /* Invalid arguments. */
+ if (top >= bottom - 1) {
+ top = 0;
+ bottom = t->t_winsize.tp_row;
+ }
+
+ /* Apply scrolling region. */
+ t->t_scrollreg.ts_begin = top;
+ t->t_scrollreg.ts_end = bottom;
+ if (t->t_stateflags & TS_ORIGIN)
+ t->t_originreg = t->t_scrollreg;
+
+ /* Home cursor to the top left of the scrolling region. */
+ t->t_cursor.tp_row = t->t_originreg.ts_begin;
+ t->t_cursor.tp_col = 0;
+ t->t_stateflags &= ~TS_WRAPPED;
+ teken_funcs_cursor(t);
+}
+
+static void
+teken_subr_single_height_double_width_line(teken_t *t __unused)
+{
+
+ teken_printf("single height double width???\n");
+}
+
+static void
+teken_subr_single_height_single_width_line(teken_t *t __unused)
+{
+
+ teken_printf("single height single width???\n");
+}
+
+static void
+teken_subr_string_terminator(teken_t *t __unused)
+{
+
+ /*
+ * Strings are already terminated in teken_input_char() when ^[
+ * is inserted.
+ */
+}
+
+static void
+teken_subr_tab_clear(teken_t *t, unsigned int cmd)
+{
+
+ switch (cmd) {
+ case 0:
+ teken_tab_clear(t, t->t_cursor.tp_col);
+ break;
+ case 3:
+ memset(&t->t_tabstops, 0, T_NUMCOL / 8);
+ break;
+ }
+}
+
+static void
+teken_subr_vertical_position_absolute(teken_t *t, unsigned int row)
+{
+
+ t->t_cursor.tp_row = t->t_originreg.ts_begin + row - 1;
+ if (t->t_cursor.tp_row >= t->t_originreg.ts_end)
+ t->t_cursor.tp_row = t->t_originreg.ts_end - 1;
+
+ t->t_stateflags &= ~TS_WRAPPED;
+ teken_funcs_cursor(t);
+}
diff --git a/teken/teken_subr_compat.h b/teken/teken_subr_compat.h
new file mode 100644
index 0000000..826a854
--- /dev/null
+++ b/teken/teken_subr_compat.h
@@ -0,0 +1,126 @@
+/*-
+ * Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/sys/teken/teken_subr_compat.h 214817 2010-11-05 00:56:21Z ed $
+ */
+
+static void
+teken_subr_cons25_set_cursor_type(teken_t *t, unsigned int type)
+{
+
+ teken_funcs_param(t, TP_SHOWCURSOR, type != 1);
+}
+
+static const teken_color_t cons25_colors[8] = { TC_BLACK, TC_BLUE,
+ TC_GREEN, TC_CYAN, TC_RED, TC_MAGENTA, TC_BROWN, TC_WHITE };
+
+static void
+teken_subr_cons25_set_adapter_background(teken_t *t, unsigned int c)
+{
+
+ t->t_defattr.ta_bgcolor = cons25_colors[c % 8];
+ t->t_curattr.ta_bgcolor = cons25_colors[c % 8];
+}
+
+static void
+teken_subr_cons25_set_adapter_foreground(teken_t *t, unsigned int c)
+{
+
+ t->t_defattr.ta_fgcolor = cons25_colors[c % 8];
+ t->t_curattr.ta_fgcolor = cons25_colors[c % 8];
+ if (c >= 8) {
+ t->t_defattr.ta_format |= TF_BOLD;
+ t->t_curattr.ta_format |= TF_BOLD;
+ } else {
+ t->t_defattr.ta_format &= ~TF_BOLD;
+ t->t_curattr.ta_format &= ~TF_BOLD;
+ }
+}
+
+static const teken_color_t cons25_revcolors[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+
+void
+teken_get_defattr_cons25(teken_t *t, int *fg, int *bg)
+{
+
+ *fg = cons25_revcolors[teken_256to8(t->t_defattr.ta_fgcolor)];
+ if (t->t_defattr.ta_format & TF_BOLD)
+ *fg += 8;
+ *bg = cons25_revcolors[teken_256to8(t->t_defattr.ta_bgcolor)];
+}
+
+static void
+teken_subr_cons25_switch_virtual_terminal(teken_t *t, unsigned int vt)
+{
+
+ teken_funcs_param(t, TP_SWITCHVT, vt);
+}
+
+static void
+teken_subr_cons25_set_bell_pitch_duration(teken_t *t, unsigned int pitch,
+ unsigned int duration)
+{
+
+ teken_funcs_param(t, TP_SETBELLPD, (pitch << 16) |
+ (duration & 0xffff));
+}
+
+static void
+teken_subr_cons25_set_graphic_rendition(teken_t *t, unsigned int cmd,
+ unsigned int param __unused)
+{
+
+ switch (cmd) {
+ case 0: /* Reset. */
+ t->t_curattr = t->t_defattr;
+ break;
+ default:
+ teken_printf("unsupported attribute %u\n", cmd);
+ }
+}
+
+static void
+teken_subr_cons25_set_terminal_mode(teken_t *t, unsigned int mode)
+{
+
+ switch (mode) {
+ case 0: /* Switch terminal to xterm. */
+ t->t_stateflags &= ~TS_CONS25;
+ break;
+ case 1: /* Switch terminal to cons25. */
+ t->t_stateflags |= TS_CONS25;
+ break;
+ }
+}
+
+#if 0
+static void
+teken_subr_vt52_decid(teken_t *t)
+{
+ const char response[] = "\x1B/Z";
+
+ teken_funcs_respond(t, response, sizeof response - 1);
+}
+#endif
diff --git a/teken/teken_wcwidth.h b/teken/teken_wcwidth.h
new file mode 100644
index 0000000..ef6da10
--- /dev/null
+++ b/teken/teken_wcwidth.h
@@ -0,0 +1,120 @@
+/*
+ * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
+ *
+ * Permission to use, copy, modify, and distribute this software
+ * for any purpose and without fee is hereby granted. The author
+ * disclaims all warranties with regard to this software.
+ *
+ * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+ *
+ * $FreeBSD: head/sys/teken/teken_wcwidth.h 186681 2009-01-01 13:26:53Z ed $
+ */
+
+struct interval {
+ teken_char_t first;
+ teken_char_t last;
+};
+
+/* auxiliary function for binary search in interval table */
+static int bisearch(teken_char_t ucs, const struct interval *table, int max) {
+ int min = 0;
+ int mid;
+
+ if (ucs < table[0].first || ucs > table[max].last)
+ return 0;
+ while (max >= min) {
+ mid = (min + max) / 2;
+ if (ucs > table[mid].last)
+ min = mid + 1;
+ else if (ucs < table[mid].first)
+ max = mid - 1;
+ else
+ return 1;
+ }
+
+ return 0;
+}
+
+static int teken_wcwidth(teken_char_t ucs)
+{
+ /* sorted list of non-overlapping intervals of non-spacing characters */
+ /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
+ static const struct interval combining[] = {
+ { 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 },
+ { 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
+ { 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 },
+ { 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 },
+ { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
+ { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
+ { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 },
+ { 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D },
+ { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 },
+ { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD },
+ { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C },
+ { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D },
+ { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
+ { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
+ { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
+ { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D },
+ { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 },
+ { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 },
+ { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC },
+ { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
+ { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D },
+ { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
+ { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
+ { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
+ { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
+ { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
+ { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 },
+ { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
+ { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 },
+ { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F },
+ { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
+ { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
+ { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
+ { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
+ { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
+ { 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 },
+ { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 },
+ { 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF },
+ { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 },
+ { 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F },
+ { 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
+ { 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F },
+ { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB },
+ { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
+ { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
+ { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
+ { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
+ { 0xE0100, 0xE01EF }
+ };
+
+ /* test for 8-bit control characters */
+ if (ucs == 0)
+ return 0;
+ if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
+ return -1;
+
+ /* binary search in table of non-spacing characters */
+ if (bisearch(ucs, combining,
+ sizeof(combining) / sizeof(struct interval) - 1))
+ return 0;
+
+ /* if we arrive here, ucs is not a combining or C0/C1 control character */
+
+ return 1 +
+ (ucs >= 0x1100 &&
+ (ucs <= 0x115f || /* Hangul Jamo init. consonants */
+ ucs == 0x2329 || ucs == 0x232a ||
+ (ucs >= 0x2e80 && ucs <= 0xa4cf &&
+ ucs != 0x303f) || /* CJK ... Yi */
+ (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
+ (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
+ (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
+ (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
+ (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
+ (ucs >= 0xffe0 && ucs <= 0xffe6) ||
+ (ucs >= 0x20000 && ucs <= 0x2fffd) ||
+ (ucs >= 0x30000 && ucs <= 0x3fffd)));
+}