summaryrefslogtreecommitdiff
path: root/usr.bin/vi/cl/cl_term.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/vi/cl/cl_term.c')
-rw-r--r--usr.bin/vi/cl/cl_term.c436
1 files changed, 436 insertions, 0 deletions
diff --git a/usr.bin/vi/cl/cl_term.c b/usr.bin/vi/cl/cl_term.c
new file mode 100644
index 00000000000..8f9088aebfb
--- /dev/null
+++ b/usr.bin/vi/cl/cl_term.c
@@ -0,0 +1,436 @@
+/*-
+ * Copyright (c) 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1993, 1994, 1995, 1996
+ * Keith Bostic. All rights reserved.
+ *
+ * See the LICENSE file for redistribution information.
+ */
+
+#include "config.h"
+
+#ifndef lint
+static const char sccsid[] = "@(#)cl_term.c 10.20 (Berkeley) 5/3/96";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+
+#include <bitstring.h>
+#include <curses.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "../common/common.h"
+#include "cl.h"
+
+static int cl_pfmap __P((SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t));
+
+/*
+ * XXX
+ * THIS REQUIRES THAT ALL SCREENS SHARE A TERMINAL TYPE.
+ */
+typedef struct _tklist {
+ char *ts; /* Key's termcap string. */
+ char *output; /* Corresponding vi command. */
+ char *name; /* Name. */
+ u_char value; /* Special value (for lookup). */
+} TKLIST;
+static TKLIST const c_tklist[] = { /* Command mappings. */
+ {"kil1", "O", "insert line"},
+ {"kdch1", "x", "delete character"},
+ {"kcud1", "j", "cursor down"},
+ {"kel", "D", "delete to eol"},
+ {"kind", "\004", "scroll down"}, /* ^D */
+ {"kll", "$", "go to eol"},
+ {"khome", "^", "go to sol"},
+ {"kich1", "i", "insert at cursor"},
+ {"kdl1", "dd", "delete line"},
+ {"kcub1", "h", "cursor left"},
+ {"knp", "\006", "page down"}, /* ^F */
+ {"kpp", "\002", "page up"}, /* ^B */
+ {"kri", "\025", "scroll up"}, /* ^U */
+ {"ked", "dG", "delete to end of screen"},
+ {"kcuf1", "l", "cursor right"},
+ {"kcuu1", "k", "cursor up"},
+ {NULL},
+};
+static TKLIST const m1_tklist[] = { /* Input mappings (lookup). */
+ {NULL},
+};
+static TKLIST const m2_tklist[] = { /* Input mappings (set or delete). */
+ {"kcud1", "\033ja", "cursor down"}, /* ^[ja */
+ {"kcub1", "\033ha", "cursor left"}, /* ^[ha */
+ {"kcuu1", "\033ka", "cursor up"}, /* ^[ka */
+ {"kcuf1", "\033la", "cursor right"}, /* ^[la */
+ {NULL},
+};
+
+/*
+ * cl_term_init --
+ * Initialize the special keys defined by the termcap/terminfo entry.
+ *
+ * PUBLIC: int cl_term_init __P((SCR *));
+ */
+int
+cl_term_init(sp)
+ SCR *sp;
+{
+ KEYLIST *kp;
+ SEQ *qp;
+ TKLIST const *tkp;
+ char *t;
+
+ /* Command mappings. */
+ for (tkp = c_tklist; tkp->name != NULL; ++tkp) {
+ if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1)
+ continue;
+ if (seq_set(sp, tkp->name, strlen(tkp->name), t, strlen(t),
+ tkp->output, strlen(tkp->output), SEQ_COMMAND,
+ SEQ_NOOVERWRITE | SEQ_SCREEN))
+ return (1);
+ }
+
+ /* Input mappings needing to be looked up. */
+ for (tkp = m1_tklist; tkp->name != NULL; ++tkp) {
+ if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1)
+ continue;
+ for (kp = keylist;; ++kp)
+ if (kp->value == tkp->value)
+ break;
+ if (kp == NULL)
+ continue;
+ if (seq_set(sp, tkp->name, strlen(tkp->name), t, strlen(t),
+ &kp->ch, 1, SEQ_INPUT, SEQ_NOOVERWRITE | SEQ_SCREEN))
+ return (1);
+ }
+
+ /* Input mappings that are already set or are text deletions. */
+ for (tkp = m2_tklist; tkp->name != NULL; ++tkp) {
+ if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1)
+ continue;
+ /*
+ * !!!
+ * Some terminals' <cursor_left> keys send single <backspace>
+ * characters. This is okay in command mapping, but not okay
+ * in input mapping. That combination is the only one we'll
+ * ever see, hopefully, so kluge it here for now.
+ */
+ if (!strcmp(t, "\b"))
+ continue;
+ if (tkp->output == NULL) {
+ if (seq_set(sp, tkp->name, strlen(tkp->name),
+ t, strlen(t), NULL, 0,
+ SEQ_INPUT, SEQ_NOOVERWRITE | SEQ_SCREEN))
+ return (1);
+ } else
+ if (seq_set(sp, tkp->name, strlen(tkp->name),
+ t, strlen(t), tkp->output, strlen(tkp->output),
+ SEQ_INPUT, SEQ_NOOVERWRITE | SEQ_SCREEN))
+ return (1);
+ }
+
+ /*
+ * Rework any function key mappings that were set before the
+ * screen was initialized.
+ */
+ for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next)
+ if (F_ISSET(qp, SEQ_FUNCMAP))
+ (void)cl_pfmap(sp, qp->stype,
+ qp->input, qp->ilen, qp->output, qp->olen);
+ return (0);
+}
+
+/*
+ * cl_term_end --
+ * End the special keys defined by the termcap/terminfo entry.
+ *
+ * PUBLIC: int cl_term_end __P((GS *));
+ */
+int
+cl_term_end(gp)
+ GS *gp;
+{
+ SEQ *qp, *nqp;
+
+ /* Delete screen specific mappings. */
+ for (qp = gp->seqq.lh_first; qp != NULL; qp = nqp) {
+ nqp = qp->q.le_next;
+ if (F_ISSET(qp, SEQ_SCREEN))
+ (void)seq_mdel(qp);
+ }
+ return (0);
+}
+
+/*
+ * cl_fmap --
+ * Map a function key.
+ *
+ * PUBLIC: int cl_fmap __P((SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t));
+ */
+int
+cl_fmap(sp, stype, from, flen, to, tlen)
+ SCR *sp;
+ seq_t stype;
+ CHAR_T *from, *to;
+ size_t flen, tlen;
+{
+ EX_INIT_IGNORE(sp);
+ VI_INIT_IGNORE(sp);
+
+ return (cl_pfmap(sp, stype, from, flen, to, tlen));
+}
+
+/*
+ * cl_pfmap --
+ * Map a function key (private version).
+ */
+static int
+cl_pfmap(sp, stype, from, flen, to, tlen)
+ SCR *sp;
+ seq_t stype;
+ CHAR_T *from, *to;
+ size_t flen, tlen;
+{
+ size_t nlen;
+ char *p, keyname[64];
+
+ (void)snprintf(keyname, sizeof(keyname), "kf%d", atoi(from + 1));
+ if ((p = tigetstr(keyname)) == NULL ||
+ p == (char *)-1 || strlen(p) == 0)
+ p = NULL;
+ if (p == NULL) {
+ msgq_str(sp, M_ERR, from, "233|This terminal has no %s key");
+ return (1);
+ }
+
+ nlen = snprintf(keyname,
+ sizeof(keyname), "function key %d", atoi(from + 1));
+ return (seq_set(sp, keyname, nlen,
+ p, strlen(p), to, tlen, stype, SEQ_NOOVERWRITE | SEQ_SCREEN));
+}
+
+/*
+ * cl_optchange --
+ * Curses screen specific "option changed" routine.
+ *
+ * PUBLIC: int cl_optchange __P((SCR *, int, char *, u_long *));
+ */
+int
+cl_optchange(sp, opt, str, valp)
+ SCR *sp;
+ int opt;
+ char *str;
+ u_long *valp;
+{
+ switch (opt) {
+ case O_COLUMNS:
+ case O_LINES:
+ case O_TERM:
+ /*
+ * Changing the columns, lines or terminal require that
+ * we restart the screen.
+ */
+ F_SET(sp->gp, G_SRESTART);
+ F_CLR(sp, SC_SCR_EX | SC_SCR_VI);
+ break;
+ case O_MESG:
+ cl_omesg(sp, CLP(sp), !*valp);
+ break;
+ }
+ return (0);
+}
+
+/*
+ * cl_omesg --
+ * Turn the tty write permission on or off.
+ *
+ * PUBLIC: int cl_omesg __P((SCR *, CL_PRIVATE *, int));
+ */
+int
+cl_omesg(sp, clp, on)
+ SCR *sp;
+ CL_PRIVATE *clp;
+ int on;
+{
+ struct stat sb;
+ char *tty;
+
+ /* Find the tty, get the current permissions. */
+ if ((tty = ttyname(STDERR_FILENO)) == NULL) {
+ if (sp != NULL)
+ msgq(sp, M_SYSERR, "stderr");
+ return (1);
+ }
+ if (stat(tty, &sb) < 0) {
+ if (sp != NULL)
+ msgq(sp, M_SYSERR, "%s", tty);
+ return (1);
+ }
+
+ /* Save the original status if it's unknown. */
+ if (clp->tgw == TGW_UNKNOWN)
+ clp->tgw = sb.st_mode & S_IWGRP ? TGW_SET : TGW_UNSET;
+
+ /* Toggle the permissions. */
+ if (on) {
+ if (chmod(tty, sb.st_mode | S_IWGRP) < 0) {
+ if (sp != NULL)
+ msgq(sp, M_SYSERR,
+ "046|messages not turned on: %s", tty);
+ return (1);
+ }
+ } else
+ if (chmod(tty, sb.st_mode & ~S_IWGRP) < 0) {
+ if (sp != NULL)
+ msgq(sp, M_SYSERR,
+ "045|messages not turned off: %s", tty);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * cl_ssize --
+ * Return the terminal size.
+ *
+ * PUBLIC: int cl_ssize __P((SCR *, int, size_t *, size_t *, int *));
+ */
+int
+cl_ssize(sp, sigwinch, rowp, colp, changedp)
+ SCR *sp;
+ int sigwinch;
+ size_t *rowp, *colp;
+ int *changedp;
+{
+#ifdef TIOCGWINSZ
+ struct winsize win;
+#endif
+ size_t col, row;
+ int rval;
+ char *p;
+
+ /* Assume it's changed. */
+ if (changedp != NULL)
+ *changedp = 1;
+
+ /*
+ * !!!
+ * sp may be NULL.
+ *
+ * Get the screen rows and columns. If the values are wrong, it's
+ * not a big deal -- as soon as the user sets them explicitly the
+ * environment will be set and the screen package will use the new
+ * values.
+ *
+ * Try TIOCGWINSZ.
+ */
+ row = col = 0;
+#ifdef TIOCGWINSZ
+ if (ioctl(STDERR_FILENO, TIOCGWINSZ, &win) != -1) {
+ row = win.ws_row;
+ col = win.ws_col;
+ }
+#endif
+ /* If here because of suspend or a signal, only trust TIOCGWINSZ. */
+ if (sigwinch) {
+ /*
+ * Somebody didn't get TIOCGWINSZ right, or has suspend
+ * without window resizing support. The user just lost,
+ * but there's nothing we can do.
+ */
+ if (row == 0 || col == 0) {
+ if (changedp != NULL)
+ *changedp = 0;
+ return (0);
+ }
+
+ /*
+ * SunOS systems deliver SIGWINCH when windows are uncovered
+ * as well as when they change size. In addition, we call
+ * here when continuing after being suspended since the window
+ * may have changed size. Since we don't want to background
+ * all of the screens just because the window was uncovered,
+ * ignore the signal if there's no change.
+ */
+ if (sp != NULL &&
+ row == O_VAL(sp, O_LINES) && col == O_VAL(sp, O_COLUMNS)) {
+ if (changedp != NULL)
+ *changedp = 0;
+ return (0);
+ }
+
+ if (rowp != NULL)
+ *rowp = row;
+ if (colp != NULL)
+ *colp = col;
+ return (0);
+ }
+
+ /*
+ * !!!
+ * If TIOCGWINSZ failed, or had entries of 0, try termcap. This
+ * routine is called before any termcap or terminal information
+ * has been set up. If there's no TERM environmental variable set,
+ * let it go, at least ex can run.
+ */
+ if (row == 0 || col == 0) {
+ if ((p = getenv("TERM")) == NULL)
+ goto noterm;
+ if (row == 0)
+ if ((rval = tigetnum("lines")) < 0)
+ msgq(sp, M_SYSERR, "tigetnum: lines");
+ else
+ row = rval;
+ if (col == 0)
+ if ((rval = tigetnum("cols")) < 0)
+ msgq(sp, M_SYSERR, "tigetnum: cols");
+ else
+ col = rval;
+ }
+
+ /* If nothing else, well, it's probably a VT100. */
+noterm: if (row == 0)
+ row = 24;
+ if (col == 0)
+ col = 80;
+
+ /*
+ * !!!
+ * POSIX 1003.2 requires the environment to override everything.
+ * Often, people can get nvi to stop messing up their screen by
+ * deleting the LINES and COLUMNS environment variables from their
+ * dot-files.
+ */
+ if ((p = getenv("LINES")) != NULL)
+ row = strtol(p, NULL, 10);
+ if ((p = getenv("COLUMNS")) != NULL)
+ col = strtol(p, NULL, 10);
+
+ if (rowp != NULL)
+ *rowp = row;
+ if (colp != NULL)
+ *colp = col;
+ return (0);
+}
+
+/*
+ * cl_putchar --
+ * Function version of putchar, for tputs.
+ *
+ * PUBLIC: int cl_putchar __P((int));
+ */
+void
+cl_putchar(ch)
+ int ch;
+{
+ putchar(ch);
+}