diff options
Diffstat (limited to 'usr.bin/vi/cl/cl_term.c')
-rw-r--r-- | usr.bin/vi/cl/cl_term.c | 436 |
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); +} |