17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5de81e71eSTim Marsland * Common Development and Distribution License (the "License").
6de81e71eSTim Marsland * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
21de81e71eSTim Marsland
227c478bd9Sstevel@tonic-gate /*
23de81e71eSTim Marsland * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
273b6e0a59SMatt Amdur /*
283b6e0a59SMatt Amdur * Copyright (c) 2012 by Delphix. All rights reserved.
29448027ebSBryan Cantrill * Copyright 2017 Joyent, Inc.
303b6e0a59SMatt Amdur */
313b6e0a59SMatt Amdur
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate * Terminal I/O Backend
347c478bd9Sstevel@tonic-gate *
357c478bd9Sstevel@tonic-gate * Terminal editing backend for standard input. The terminal i/o backend is
367c478bd9Sstevel@tonic-gate * actually built on top of two other i/o backends: one for raw input and
377c478bd9Sstevel@tonic-gate * another for raw output (presumably stdin and stdout). When IOP_READ is
387c478bd9Sstevel@tonic-gate * invoked, the terminal backend enters a read-loop in which it can perform
397c478bd9Sstevel@tonic-gate * command-line editing and access a history buffer. Once a newline is read,
407c478bd9Sstevel@tonic-gate * the entire buffered command-line is returned to the caller. The termio
417c478bd9Sstevel@tonic-gate * code makes use of a command buffer (see mdb_cmdbuf.c) to maintain and
427c478bd9Sstevel@tonic-gate * manipulate the state of a command line, and store it for re-use in a
437c478bd9Sstevel@tonic-gate * history list. The termio code manipulates the terminal to keep it in
447c478bd9Sstevel@tonic-gate * sync with the contents of the command buffer, and moves the cursor in
457c478bd9Sstevel@tonic-gate * response to editing commands.
467c478bd9Sstevel@tonic-gate *
477c478bd9Sstevel@tonic-gate * The terminal backend is also responsible for maintaining and manipulating
48bbf21555SRichard Lowe * the settings (see stty(1) and termio(4I)) associated with the terminal.
497c478bd9Sstevel@tonic-gate * The debugger makes use of four distinct sets of terminal attributes:
507c478bd9Sstevel@tonic-gate *
517c478bd9Sstevel@tonic-gate * (1) the settings used by the debugger's parent process (tio_ptios),
527c478bd9Sstevel@tonic-gate * (2) the settings used by a controlled child process (tio_ctios),
537c478bd9Sstevel@tonic-gate * (3) the settings used for reading and command-line editing (tio_rtios), and
547c478bd9Sstevel@tonic-gate * (4) the settings used when mdb dcmds are executing (tio_dtios).
557c478bd9Sstevel@tonic-gate *
567c478bd9Sstevel@tonic-gate * The parent settings (1) are read from the terminal during initialization.
577c478bd9Sstevel@tonic-gate * These settings are restored before the debugger exits or when it is stopped
587c478bd9Sstevel@tonic-gate * by SIGTSTP. The child settings (2) are initially a copy of (1), but are
597c478bd9Sstevel@tonic-gate * then restored prior to continuing execution of a victim process. The new
607c478bd9Sstevel@tonic-gate * settings (3) and (4) are both derived from (1). The raw settings (3) used
617c478bd9Sstevel@tonic-gate * for reading from the terminal allow the terminal code to respond instantly
627c478bd9Sstevel@tonic-gate * to keypresses and perform all the necessary handling. The dcmd settings (4)
637c478bd9Sstevel@tonic-gate * are essentially the same as (1), except that we make sure ISIG is enabled
647c478bd9Sstevel@tonic-gate * so that we will receive asynchronous SIGINT notification from the terminal
657c478bd9Sstevel@tonic-gate * driver if the user types the interrupt character (typically ^C).
667c478bd9Sstevel@tonic-gate */
677c478bd9Sstevel@tonic-gate
687c478bd9Sstevel@tonic-gate #include <setjmp.h>
697c478bd9Sstevel@tonic-gate #include <unistd.h>
707c478bd9Sstevel@tonic-gate #include <stdlib.h>
717c478bd9Sstevel@tonic-gate #include <limits.h>
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate #include <mdb/mdb_types.h>
747c478bd9Sstevel@tonic-gate #include <mdb/mdb_cmdbuf.h>
757c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h>
767c478bd9Sstevel@tonic-gate #include <mdb/mdb_io_impl.h>
777c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h>
787c478bd9Sstevel@tonic-gate #include <mdb/mdb_signal.h>
797c478bd9Sstevel@tonic-gate #include <mdb/mdb_callb.h>
807c478bd9Sstevel@tonic-gate #include <mdb/mdb_stdlib.h>
817c478bd9Sstevel@tonic-gate #include <mdb/mdb_string.h>
827c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
837c478bd9Sstevel@tonic-gate #include <mdb/mdb_frame.h>
843b6e0a59SMatt Amdur #include <mdb/mdb_tab.h>
857c478bd9Sstevel@tonic-gate #include <mdb/mdb.h>
867c478bd9Sstevel@tonic-gate
877c478bd9Sstevel@tonic-gate #ifdef ERR
887c478bd9Sstevel@tonic-gate #undef ERR
897c478bd9Sstevel@tonic-gate #endif
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gate #include <curses.h>
927c478bd9Sstevel@tonic-gate
937c478bd9Sstevel@tonic-gate #define KEY_ESC (0x01b) /* Escape key code */
947c478bd9Sstevel@tonic-gate #define KEY_DEL (0x07f) /* ASCII DEL key code */
957c478bd9Sstevel@tonic-gate
96892f67e4SJoshua M. Clulow /*
97892f67e4SJoshua M. Clulow * These macros support the use of various ranges within the "tio_keymap"
98892f67e4SJoshua M. Clulow * member of "termio_data_t" objects. This array maps from an input byte, or
99892f67e4SJoshua M. Clulow * special control code, to the appropriate terminal handling callback. The
100892f67e4SJoshua M. Clulow * array has KEY_MAX (0x1ff) entries, partitioned as follows:
101892f67e4SJoshua M. Clulow *
102892f67e4SJoshua M. Clulow * 0 - 7f 7-bit ASCII byte
103892f67e4SJoshua M. Clulow * 80 - ff META() ASCII byte with Meta key modifier
104892f67e4SJoshua M. Clulow * 100 - 119 KPAD() Alphabetic character received as part of a single-byte
105892f67e4SJoshua M. Clulow * cursor control sequence, e.g. ESC [ A
106892f67e4SJoshua M. Clulow * 11a - 123 FKEY() Numeric character received as part of a function key
107892f67e4SJoshua M. Clulow * control sequence, e.g. ESC [ 4 ~
108892f67e4SJoshua M. Clulow * 124 - 1ff Unused
109892f67e4SJoshua M. Clulow */
110892f67e4SJoshua M. Clulow #define META(c) (((c) & 0x7f) | 0x80)
111892f67e4SJoshua M. Clulow #define KPAD(c) (((c) < 'A' || (c) > 'Z') ? 0 : ((c) - 'A' + 0x100))
112892f67e4SJoshua M. Clulow #define FKEY(c) (((c) < '0' || (c) > '9') ? 0 : ((c) - '0' + 0x11a))
1137c478bd9Sstevel@tonic-gate
1147c478bd9Sstevel@tonic-gate /*
1157c478bd9Sstevel@tonic-gate * These macros allow for composition of control sequences for xterm and other
1167c478bd9Sstevel@tonic-gate * terminals that support certain features of the VT102 and later VT terminals.
1177c478bd9Sstevel@tonic-gate * Refer to the classic monograph "Xterm Control Sequences" for more info.
1187c478bd9Sstevel@tonic-gate */
1197c478bd9Sstevel@tonic-gate #define TI_DECSET(Pm) "\033[?" Pm "h" /* Compose DEC private mode set */
1207c478bd9Sstevel@tonic-gate #define TI_DECRST(Pm) "\033[?" Pm "l" /* Compose DEC private mode reset */
1217c478bd9Sstevel@tonic-gate #define TI_DECSAV(Pm) "\033[?" Pm "s" /* Compose DEC private mode save */
1227c478bd9Sstevel@tonic-gate #define TI_DECRES(Pm) "\033[?" Pm "r" /* Compose DEC private mode restore */
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate #define TI_DECCOLM "3" /* Ps = DEC 80/132 column mode */
1257c478bd9Sstevel@tonic-gate #define TI_COLENAB "40" /* Ps = 80/132 column switch enable */
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate #define TIO_DEFAULT_ROWS 24 /* Default number of rows */
1287c478bd9Sstevel@tonic-gate #define TIO_DEFAULT_COLS 80 /* Default number of columns */
1297c478bd9Sstevel@tonic-gate
1307c478bd9Sstevel@tonic-gate typedef union termio_attr_val {
1317c478bd9Sstevel@tonic-gate const char *at_str; /* String value */
1327c478bd9Sstevel@tonic-gate int at_val; /* Integer or boolean value */
1337c478bd9Sstevel@tonic-gate } termio_attr_val_t;
1347c478bd9Sstevel@tonic-gate
1357c478bd9Sstevel@tonic-gate typedef struct termio_info {
1367c478bd9Sstevel@tonic-gate termio_attr_val_t ti_cub1; /* Move back one space */
1377c478bd9Sstevel@tonic-gate termio_attr_val_t ti_cuf1; /* Move forward one space */
1387c478bd9Sstevel@tonic-gate termio_attr_val_t ti_cuu1; /* Move up one line */
1397c478bd9Sstevel@tonic-gate termio_attr_val_t ti_cud1; /* Move down one line */
1407c478bd9Sstevel@tonic-gate termio_attr_val_t ti_pad; /* Pad character */
1417c478bd9Sstevel@tonic-gate termio_attr_val_t ti_el; /* Clear to end-of-line */
1427c478bd9Sstevel@tonic-gate termio_attr_val_t ti_am; /* Automatic right margin? */
1437c478bd9Sstevel@tonic-gate termio_attr_val_t ti_bw; /* Backward motion at left edge? */
1447c478bd9Sstevel@tonic-gate termio_attr_val_t ti_npc; /* No padding character? */
145448027ebSBryan Cantrill termio_attr_val_t ti_xenl; /* Newline ignored at autowrap? */
1467c478bd9Sstevel@tonic-gate termio_attr_val_t ti_xon; /* Use xon/xoff handshaking? */
1477c478bd9Sstevel@tonic-gate termio_attr_val_t ti_cols; /* # of columns */
1487c478bd9Sstevel@tonic-gate termio_attr_val_t ti_lines; /* # of rows */
1497c478bd9Sstevel@tonic-gate termio_attr_val_t ti_pb; /* Lowest baud rate that requires pad */
1507c478bd9Sstevel@tonic-gate termio_attr_val_t ti_smso; /* Set standout mode */
1517c478bd9Sstevel@tonic-gate termio_attr_val_t ti_rmso; /* Remove standout mode */
1527c478bd9Sstevel@tonic-gate termio_attr_val_t ti_smul; /* Set underline mode */
1537c478bd9Sstevel@tonic-gate termio_attr_val_t ti_rmul; /* Remove underline mode */
1547c478bd9Sstevel@tonic-gate termio_attr_val_t ti_enacs; /* Enable alternate character set */
1557c478bd9Sstevel@tonic-gate termio_attr_val_t ti_smacs; /* Set alternate character set */
1567c478bd9Sstevel@tonic-gate termio_attr_val_t ti_rmacs; /* Remove alternate character set */
1577c478bd9Sstevel@tonic-gate termio_attr_val_t ti_smcup; /* Set mode where cup is active */
1587c478bd9Sstevel@tonic-gate termio_attr_val_t ti_rmcup; /* Remove mode where cup is active */
1597c478bd9Sstevel@tonic-gate termio_attr_val_t ti_rev; /* Set reverse video mode */
1607c478bd9Sstevel@tonic-gate termio_attr_val_t ti_bold; /* Set bold text mode */
1617c478bd9Sstevel@tonic-gate termio_attr_val_t ti_dim; /* Set dim text mode */
1627c478bd9Sstevel@tonic-gate termio_attr_val_t ti_sgr0; /* Remove all video attributes */
1637c478bd9Sstevel@tonic-gate termio_attr_val_t ti_smir; /* Set insert mode */
1647c478bd9Sstevel@tonic-gate termio_attr_val_t ti_rmir; /* Remove insert mode */
1657c478bd9Sstevel@tonic-gate termio_attr_val_t ti_ich1; /* Insert character */
1667c478bd9Sstevel@tonic-gate termio_attr_val_t ti_ip; /* Insert pad delay in msecs */
1677c478bd9Sstevel@tonic-gate termio_attr_val_t ti_clear; /* Clear screen and home cursor */
1687c478bd9Sstevel@tonic-gate termio_attr_val_t ti_cnorm; /* Make cursor appear normal */
1697c478bd9Sstevel@tonic-gate termio_attr_val_t ti_nel; /* Newline */
1707c478bd9Sstevel@tonic-gate termio_attr_val_t ti_cr; /* Carriage return */
171448027ebSBryan Cantrill termio_attr_val_t ti_smam; /* Turn on automatic margins */
1727c478bd9Sstevel@tonic-gate } termio_info_t;
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate typedef enum {
1757c478bd9Sstevel@tonic-gate TIO_ATTR_REQSTR, /* String attribute that is required */
1767c478bd9Sstevel@tonic-gate TIO_ATTR_STR, /* String attribute */
1777c478bd9Sstevel@tonic-gate TIO_ATTR_BOOL, /* Boolean attribute */
1787c478bd9Sstevel@tonic-gate TIO_ATTR_INT /* Integer attribute */
1797c478bd9Sstevel@tonic-gate } termio_attr_type_t;
1807c478bd9Sstevel@tonic-gate
1817c478bd9Sstevel@tonic-gate typedef struct termio_attr {
1827c478bd9Sstevel@tonic-gate const char *ta_name; /* Capability name */
1837c478bd9Sstevel@tonic-gate termio_attr_type_t ta_type; /* Capability type */
1847c478bd9Sstevel@tonic-gate termio_attr_val_t *ta_valp; /* String pointer location */
1857c478bd9Sstevel@tonic-gate } termio_attr_t;
1867c478bd9Sstevel@tonic-gate
1877c478bd9Sstevel@tonic-gate struct termio_data;
1887c478bd9Sstevel@tonic-gate typedef const char *(*keycb_t)(struct termio_data *, int);
1897c478bd9Sstevel@tonic-gate typedef void (*putp_t)(struct termio_data *, const char *, uint_t);
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate #define TIO_FINDHIST 0x01 /* Find-history-mode */
1927c478bd9Sstevel@tonic-gate #define TIO_AUTOWRAP 0x02 /* Terminal has autowrap */
1937c478bd9Sstevel@tonic-gate #define TIO_BACKLEFT 0x04 /* Terminal can go back at left edge */
1947c478bd9Sstevel@tonic-gate #define TIO_INSERT 0x08 /* Terminal has insert mode */
1957c478bd9Sstevel@tonic-gate #define TIO_USECUP 0x10 /* Use smcup/rmcup sequences */
1967c478bd9Sstevel@tonic-gate #define TIO_TTYWARN 0x20 /* Warnings about tty issued */
1977c478bd9Sstevel@tonic-gate #define TIO_CAPWARN 0x40 /* Warnings about terminfo issued */
1987c478bd9Sstevel@tonic-gate #define TIO_XTERM 0x80 /* Terminal is xterm compatible */
1993b6e0a59SMatt Amdur #define TIO_TAB 0x100 /* Tab completion mode */
200448027ebSBryan Cantrill #define TIO_LAZYWRAP 0x200 /* Lazy cursor on autowrap */
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate static const mdb_bitmask_t tio_flag_masks[] = {
2037c478bd9Sstevel@tonic-gate { "FINDHIST", TIO_FINDHIST, TIO_FINDHIST },
2047c478bd9Sstevel@tonic-gate { "AUTOWRAP", TIO_AUTOWRAP, TIO_AUTOWRAP },
2057c478bd9Sstevel@tonic-gate { "BACKLEFT", TIO_BACKLEFT, TIO_BACKLEFT },
2067c478bd9Sstevel@tonic-gate { "INSERT", TIO_INSERT, TIO_INSERT },
2077c478bd9Sstevel@tonic-gate { "USECUP", TIO_USECUP, TIO_USECUP },
2087c478bd9Sstevel@tonic-gate { "TTYWARN", TIO_TTYWARN, TIO_TTYWARN },
2097c478bd9Sstevel@tonic-gate { "CAPWARN", TIO_CAPWARN, TIO_CAPWARN },
2107c478bd9Sstevel@tonic-gate { "XTERM", TIO_XTERM, TIO_XTERM },
211448027ebSBryan Cantrill { "TAB", TIO_TAB, TIO_TAB },
212448027ebSBryan Cantrill { "LAZYWRAP", TIO_LAZYWRAP, TIO_LAZYWRAP },
2137c478bd9Sstevel@tonic-gate { NULL, 0, 0 }
2147c478bd9Sstevel@tonic-gate };
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate typedef struct termio_data {
2177c478bd9Sstevel@tonic-gate mdb_io_t *tio_io; /* Pointer back to containing i/o */
2187c478bd9Sstevel@tonic-gate mdb_io_t *tio_out_io; /* Terminal output backend */
2197c478bd9Sstevel@tonic-gate mdb_io_t *tio_in_io; /* Terminal input backend */
2207c478bd9Sstevel@tonic-gate mdb_iob_t *tio_out; /* I/o buffer for terminal output */
2217c478bd9Sstevel@tonic-gate mdb_iob_t *tio_in; /* I/o buffer for terminal input */
2227c478bd9Sstevel@tonic-gate mdb_iob_t *tio_link; /* I/o buffer to resize on WINCH */
223892f67e4SJoshua M. Clulow keycb_t tio_keymap[KEY_MAX]; /* Keymap (see comments atop file) */
2247c478bd9Sstevel@tonic-gate mdb_cmdbuf_t tio_cmdbuf; /* Editable command-line buffer */
2257c478bd9Sstevel@tonic-gate struct termios tio_ptios; /* Parent terminal settings */
2267c478bd9Sstevel@tonic-gate struct termios tio_ctios; /* Child terminal settings */
2277c478bd9Sstevel@tonic-gate struct termios tio_rtios; /* Settings for read loop */
2287c478bd9Sstevel@tonic-gate struct termios tio_dtios; /* Settings for dcmd execution */
2297c478bd9Sstevel@tonic-gate sigjmp_buf tio_env; /* Read loop setjmp(3c) environment */
2307c478bd9Sstevel@tonic-gate termio_info_t tio_info; /* Terminal attribute strings */
2317c478bd9Sstevel@tonic-gate char *tio_attrs; /* Attribute string buffer */
2327c478bd9Sstevel@tonic-gate size_t tio_attrslen; /* Length in bytes of tio_attrs */
2337c478bd9Sstevel@tonic-gate const char *tio_prompt; /* Prompt string for this read */
2347c478bd9Sstevel@tonic-gate size_t tio_promptlen; /* Length of prompt string */
2357c478bd9Sstevel@tonic-gate size_t tio_rows; /* Terminal height */
2367c478bd9Sstevel@tonic-gate size_t tio_cols; /* Terminal width */
2377c478bd9Sstevel@tonic-gate size_t tio_x; /* Cursor x coordinate */
2387c478bd9Sstevel@tonic-gate size_t tio_y; /* Cursor y coordinate */
2397c478bd9Sstevel@tonic-gate size_t tio_max_x; /* Previous maximum x coordinate */
2407c478bd9Sstevel@tonic-gate size_t tio_max_y; /* Previous maximum y coordinate */
2417c478bd9Sstevel@tonic-gate int tio_intr; /* Interrupt char */
2427c478bd9Sstevel@tonic-gate int tio_quit; /* Quit char */
2437c478bd9Sstevel@tonic-gate int tio_erase; /* Erase char */
2447c478bd9Sstevel@tonic-gate int tio_werase; /* Word-erase char */
2457c478bd9Sstevel@tonic-gate int tio_kill; /* Kill char */
2467c478bd9Sstevel@tonic-gate int tio_eof; /* End-of-file char */
2477c478bd9Sstevel@tonic-gate int tio_susp; /* Suspend char */
2487c478bd9Sstevel@tonic-gate uint_t tio_flags; /* Miscellaneous flags */
2497c478bd9Sstevel@tonic-gate volatile mdb_bool_t tio_active; /* Flag denoting read loop active */
2507c478bd9Sstevel@tonic-gate volatile mdb_bool_t tio_rti_on; /* Flag denoting rtios in use */
2517c478bd9Sstevel@tonic-gate putp_t tio_putp; /* termio_tput() subroutine */
2527c478bd9Sstevel@tonic-gate uint_t tio_baud; /* Baud rate (chars per second) */
2537c478bd9Sstevel@tonic-gate uint_t tio_usecpc; /* Usecs per char at given baud rate */
2547c478bd9Sstevel@tonic-gate pid_t tio_opgid; /* Old process group id for terminal */
2557c478bd9Sstevel@tonic-gate uint_t tio_suspended; /* termio_suspend_tty() nesting count */
2567c478bd9Sstevel@tonic-gate } termio_data_t;
2577c478bd9Sstevel@tonic-gate
2587c478bd9Sstevel@tonic-gate static ssize_t termio_read(mdb_io_t *, void *, size_t);
2597c478bd9Sstevel@tonic-gate static ssize_t termio_write(mdb_io_t *, const void *, size_t);
2607c478bd9Sstevel@tonic-gate static off64_t termio_seek(mdb_io_t *, off64_t, int);
2617c478bd9Sstevel@tonic-gate static int termio_ctl(mdb_io_t *, int, void *);
2627c478bd9Sstevel@tonic-gate static void termio_close(mdb_io_t *);
2637c478bd9Sstevel@tonic-gate static const char *termio_name(mdb_io_t *);
2647c478bd9Sstevel@tonic-gate static void termio_link(mdb_io_t *, mdb_iob_t *);
2657c478bd9Sstevel@tonic-gate static void termio_unlink(mdb_io_t *, mdb_iob_t *);
2667c478bd9Sstevel@tonic-gate static int termio_setattr(mdb_io_t *, int, uint_t);
2677c478bd9Sstevel@tonic-gate static void termio_suspend(mdb_io_t *);
2687c478bd9Sstevel@tonic-gate static void termio_resume(mdb_io_t *);
2697c478bd9Sstevel@tonic-gate
2707c478bd9Sstevel@tonic-gate static void termio_suspend_tty(termio_data_t *, struct termios *);
2717c478bd9Sstevel@tonic-gate static void termio_resume_tty(termio_data_t *, struct termios *);
2727c478bd9Sstevel@tonic-gate
2737c478bd9Sstevel@tonic-gate static void termio_putp(termio_data_t *, const char *, uint_t);
2747c478bd9Sstevel@tonic-gate static void termio_puts(termio_data_t *, const char *, uint_t);
2757c478bd9Sstevel@tonic-gate static void termio_tput(termio_data_t *, const char *, uint_t);
2767c478bd9Sstevel@tonic-gate static void termio_addch(termio_data_t *, char, size_t);
2777c478bd9Sstevel@tonic-gate static void termio_insch(termio_data_t *, char, size_t);
2787c478bd9Sstevel@tonic-gate static void termio_mvcur(termio_data_t *);
2797c478bd9Sstevel@tonic-gate static void termio_bspch(termio_data_t *);
2807c478bd9Sstevel@tonic-gate static void termio_delch(termio_data_t *);
2817c478bd9Sstevel@tonic-gate static void termio_clear(termio_data_t *);
2827c478bd9Sstevel@tonic-gate static void termio_redraw(termio_data_t *);
2837c478bd9Sstevel@tonic-gate static void termio_prompt(termio_data_t *);
2847c478bd9Sstevel@tonic-gate
2853b6e0a59SMatt Amdur static const char *termio_tab(termio_data_t *, int);
2867c478bd9Sstevel@tonic-gate static const char *termio_insert(termio_data_t *, int);
2877c478bd9Sstevel@tonic-gate static const char *termio_accept(termio_data_t *, int);
2887c478bd9Sstevel@tonic-gate static const char *termio_backspace(termio_data_t *, int);
2897c478bd9Sstevel@tonic-gate static const char *termio_delchar(termio_data_t *, int);
2907c478bd9Sstevel@tonic-gate static const char *termio_fwdchar(termio_data_t *, int);
2917c478bd9Sstevel@tonic-gate static const char *termio_backchar(termio_data_t *, int);
2927c478bd9Sstevel@tonic-gate static const char *termio_transpose(termio_data_t *, int);
2937c478bd9Sstevel@tonic-gate static const char *termio_home(termio_data_t *, int);
2947c478bd9Sstevel@tonic-gate static const char *termio_end(termio_data_t *, int);
2957c478bd9Sstevel@tonic-gate static const char *termio_fwdword(termio_data_t *, int);
2967c478bd9Sstevel@tonic-gate static const char *termio_backword(termio_data_t *, int);
2977c478bd9Sstevel@tonic-gate static const char *termio_kill(termio_data_t *, int);
2987c478bd9Sstevel@tonic-gate static const char *termio_killfwdword(termio_data_t *, int);
2997c478bd9Sstevel@tonic-gate static const char *termio_killbackword(termio_data_t *, int);
3007c478bd9Sstevel@tonic-gate static const char *termio_reset(termio_data_t *, int);
3017c478bd9Sstevel@tonic-gate static const char *termio_widescreen(termio_data_t *, int);
3027c478bd9Sstevel@tonic-gate static const char *termio_prevhist(termio_data_t *, int);
3037c478bd9Sstevel@tonic-gate static const char *termio_nexthist(termio_data_t *, int);
3047c478bd9Sstevel@tonic-gate static const char *termio_accel(termio_data_t *, int);
3057c478bd9Sstevel@tonic-gate static const char *termio_findhist(termio_data_t *, int);
3067c478bd9Sstevel@tonic-gate static const char *termio_refresh(termio_data_t *, int);
3077c478bd9Sstevel@tonic-gate
3087c478bd9Sstevel@tonic-gate static const char *termio_intr(termio_data_t *, int);
3097c478bd9Sstevel@tonic-gate static const char *termio_quit(termio_data_t *, int);
3107c478bd9Sstevel@tonic-gate static const char *termio_susp(termio_data_t *, int);
3117c478bd9Sstevel@tonic-gate
3127c478bd9Sstevel@tonic-gate static void termio_winch(int, siginfo_t *, ucontext_t *, void *);
3137c478bd9Sstevel@tonic-gate static void termio_tstp(int, siginfo_t *, ucontext_t *, void *);
3147c478bd9Sstevel@tonic-gate
3157c478bd9Sstevel@tonic-gate extern const char *tigetstr(const char *);
3167c478bd9Sstevel@tonic-gate extern int tigetflag(const char *);
3177c478bd9Sstevel@tonic-gate extern int tigetnum(const char *);
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate static const mdb_io_ops_t termio_ops = {
3200c1b95beSRichard Lowe .io_read = termio_read,
3210c1b95beSRichard Lowe .io_write = termio_write,
3220c1b95beSRichard Lowe .io_seek = termio_seek,
3230c1b95beSRichard Lowe .io_ctl = termio_ctl,
3240c1b95beSRichard Lowe .io_close = termio_close,
3250c1b95beSRichard Lowe .io_name = termio_name,
3260c1b95beSRichard Lowe .io_link = termio_link,
3270c1b95beSRichard Lowe .io_unlink = termio_unlink,
3280c1b95beSRichard Lowe .io_setattr = termio_setattr,
3290c1b95beSRichard Lowe .io_suspend = termio_suspend,
3300c1b95beSRichard Lowe .io_resume = termio_resume,
3317c478bd9Sstevel@tonic-gate };
3327c478bd9Sstevel@tonic-gate
3337c478bd9Sstevel@tonic-gate static termio_info_t termio_info;
3347c478bd9Sstevel@tonic-gate
3357c478bd9Sstevel@tonic-gate static const termio_attr_t termio_attrs[] = {
3367c478bd9Sstevel@tonic-gate { "cub1", TIO_ATTR_REQSTR, &termio_info.ti_cub1 },
3377c478bd9Sstevel@tonic-gate { "cuf1", TIO_ATTR_REQSTR, &termio_info.ti_cuf1 },
3387c478bd9Sstevel@tonic-gate { "cuu1", TIO_ATTR_REQSTR, &termio_info.ti_cuu1 },
3397c478bd9Sstevel@tonic-gate { "cud1", TIO_ATTR_REQSTR, &termio_info.ti_cud1 },
3407c478bd9Sstevel@tonic-gate { "pad", TIO_ATTR_STR, &termio_info.ti_pad },
3417c478bd9Sstevel@tonic-gate { "el", TIO_ATTR_REQSTR, &termio_info.ti_el },
3427c478bd9Sstevel@tonic-gate { "am", TIO_ATTR_BOOL, &termio_info.ti_am },
3437c478bd9Sstevel@tonic-gate { "bw", TIO_ATTR_BOOL, &termio_info.ti_bw },
3447c478bd9Sstevel@tonic-gate { "npc", TIO_ATTR_BOOL, &termio_info.ti_npc },
3457c478bd9Sstevel@tonic-gate { "xenl", TIO_ATTR_BOOL, &termio_info.ti_xenl },
3467c478bd9Sstevel@tonic-gate { "xon", TIO_ATTR_BOOL, &termio_info.ti_xon },
3477c478bd9Sstevel@tonic-gate { "cols", TIO_ATTR_INT, &termio_info.ti_cols },
3487c478bd9Sstevel@tonic-gate { "lines", TIO_ATTR_INT, &termio_info.ti_lines },
3497c478bd9Sstevel@tonic-gate { "pb", TIO_ATTR_INT, &termio_info.ti_pb },
3507c478bd9Sstevel@tonic-gate { "smso", TIO_ATTR_STR, &termio_info.ti_smso },
3517c478bd9Sstevel@tonic-gate { "rmso", TIO_ATTR_STR, &termio_info.ti_rmso },
3527c478bd9Sstevel@tonic-gate { "smul", TIO_ATTR_STR, &termio_info.ti_smul },
3537c478bd9Sstevel@tonic-gate { "rmul", TIO_ATTR_STR, &termio_info.ti_rmul },
3547c478bd9Sstevel@tonic-gate { "enacs", TIO_ATTR_STR, &termio_info.ti_enacs },
3557c478bd9Sstevel@tonic-gate { "smacs", TIO_ATTR_STR, &termio_info.ti_smacs },
3567c478bd9Sstevel@tonic-gate { "rmacs", TIO_ATTR_STR, &termio_info.ti_rmacs },
3577c478bd9Sstevel@tonic-gate { "smcup", TIO_ATTR_STR, &termio_info.ti_smcup },
3587c478bd9Sstevel@tonic-gate { "rmcup", TIO_ATTR_STR, &termio_info.ti_rmcup },
3597c478bd9Sstevel@tonic-gate { "rev", TIO_ATTR_STR, &termio_info.ti_rev },
3607c478bd9Sstevel@tonic-gate { "bold", TIO_ATTR_STR, &termio_info.ti_bold },
3617c478bd9Sstevel@tonic-gate { "dim", TIO_ATTR_STR, &termio_info.ti_dim },
3627c478bd9Sstevel@tonic-gate { "sgr0", TIO_ATTR_STR, &termio_info.ti_sgr0 },
3637c478bd9Sstevel@tonic-gate { "smir", TIO_ATTR_STR, &termio_info.ti_smir },
3647c478bd9Sstevel@tonic-gate { "rmir", TIO_ATTR_STR, &termio_info.ti_rmir },
3657c478bd9Sstevel@tonic-gate { "ich1", TIO_ATTR_STR, &termio_info.ti_ich1 },
3667c478bd9Sstevel@tonic-gate { "ip", TIO_ATTR_STR, &termio_info.ti_ip },
3677c478bd9Sstevel@tonic-gate { "clear", TIO_ATTR_STR, &termio_info.ti_clear },
3687c478bd9Sstevel@tonic-gate { "cnorm", TIO_ATTR_STR, &termio_info.ti_cnorm },
3697c478bd9Sstevel@tonic-gate { "nel", TIO_ATTR_STR, &termio_info.ti_nel },
3707c478bd9Sstevel@tonic-gate { "cr", TIO_ATTR_STR, &termio_info.ti_cr },
371448027ebSBryan Cantrill { "smam", TIO_ATTR_STR, &termio_info.ti_smam },
372892ad162SToomas Soome { NULL, 0, NULL }
3737c478bd9Sstevel@tonic-gate };
3747c478bd9Sstevel@tonic-gate
3757c478bd9Sstevel@tonic-gate /*
3767c478bd9Sstevel@tonic-gate * One-key accelerators. Some commands are used so frequently as to need
3777c478bd9Sstevel@tonic-gate * single-key equivalents. termio_accelkeys contains a list of the accelerator
3787c478bd9Sstevel@tonic-gate * keys, with termio_accel listing the accelerated commands. The array is
3797c478bd9Sstevel@tonic-gate * indexed by the offset of the accelerator in the macro string, and as such
3807c478bd9Sstevel@tonic-gate * *must* stay in the same order.
3817c478bd9Sstevel@tonic-gate */
3827c478bd9Sstevel@tonic-gate static const char *const termio_accelkeys = "[]";
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate static const char *const termio_accelstrings[] = {
3857c478bd9Sstevel@tonic-gate "::step over", /* [ */
3867c478bd9Sstevel@tonic-gate "::step" /* ] */
3877c478bd9Sstevel@tonic-gate };
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate static const char *
termio_accel_lookup(int c)3907c478bd9Sstevel@tonic-gate termio_accel_lookup(int c)
3917c478bd9Sstevel@tonic-gate {
3927c478bd9Sstevel@tonic-gate const char *acc;
3937c478bd9Sstevel@tonic-gate
3947c478bd9Sstevel@tonic-gate if ((acc = strchr(termio_accelkeys, c)) == NULL)
3957c478bd9Sstevel@tonic-gate return (NULL);
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate return (termio_accelstrings[(int)(acc - termio_accelkeys)]);
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate static ssize_t
termio_read(mdb_io_t * io,void * buf,size_t nbytes)4017c478bd9Sstevel@tonic-gate termio_read(mdb_io_t *io, void *buf, size_t nbytes)
4027c478bd9Sstevel@tonic-gate {
4037c478bd9Sstevel@tonic-gate termio_data_t *td = io->io_data;
4047c478bd9Sstevel@tonic-gate
4057c478bd9Sstevel@tonic-gate mdb_bool_t esc = FALSE, pad = FALSE;
4067c478bd9Sstevel@tonic-gate ssize_t rlen = 0;
407892f67e4SJoshua M. Clulow int c, fkey = 0;
4087c478bd9Sstevel@tonic-gate
4097c478bd9Sstevel@tonic-gate const char *s;
4107c478bd9Sstevel@tonic-gate size_t len;
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gate if (io->io_next != NULL)
4137c478bd9Sstevel@tonic-gate return (IOP_READ(io->io_next, buf, nbytes));
4147c478bd9Sstevel@tonic-gate
4157c478bd9Sstevel@tonic-gate td->tio_rti_on = TRUE;
4167c478bd9Sstevel@tonic-gate if (termio_ctl(td->tio_io, TCSETSW, &td->tio_rtios) == -1)
4177c478bd9Sstevel@tonic-gate warn("failed to set terminal attributes");
4187c478bd9Sstevel@tonic-gate
4197c478bd9Sstevel@tonic-gate if (nbytes == 1) {
4207c478bd9Sstevel@tonic-gate if ((c = mdb_iob_getc(td->tio_in)) == EOF)
4217c478bd9Sstevel@tonic-gate goto out;
4227c478bd9Sstevel@tonic-gate
4237c478bd9Sstevel@tonic-gate *((uchar_t *)buf) = (uchar_t)c;
4247c478bd9Sstevel@tonic-gate
4257c478bd9Sstevel@tonic-gate rlen = 1;
4267c478bd9Sstevel@tonic-gate goto out;
4277c478bd9Sstevel@tonic-gate }
4287c478bd9Sstevel@tonic-gate
4293b6e0a59SMatt Amdur if (td->tio_flags & TIO_TAB)
4303b6e0a59SMatt Amdur termio_redraw(td);
4313b6e0a59SMatt Amdur else
4323b6e0a59SMatt Amdur termio_prompt(td);
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate /*
4357c478bd9Sstevel@tonic-gate * We need to redraw the entire command-line and restart our read loop
4367c478bd9Sstevel@tonic-gate * in the event of a SIGWINCH or resume following SIGTSTP (SIGCONT).
4377c478bd9Sstevel@tonic-gate */
4387c478bd9Sstevel@tonic-gate if (sigsetjmp(td->tio_env, 1) != 0) {
4397c478bd9Sstevel@tonic-gate td->tio_active = FALSE;
4407c478bd9Sstevel@tonic-gate td->tio_x = td->tio_y = 0;
4417c478bd9Sstevel@tonic-gate
4427c478bd9Sstevel@tonic-gate len = td->tio_cmdbuf.cmd_buflen + td->tio_promptlen;
4437c478bd9Sstevel@tonic-gate td->tio_max_x = len % td->tio_cols;
4447c478bd9Sstevel@tonic-gate td->tio_max_y = len / td->tio_cols;
4457c478bd9Sstevel@tonic-gate
4467c478bd9Sstevel@tonic-gate esc = pad = FALSE;
4477c478bd9Sstevel@tonic-gate
4487c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_cr.at_str, 1);
4497c478bd9Sstevel@tonic-gate mdb_iob_flush(td->tio_out);
4507c478bd9Sstevel@tonic-gate termio_redraw(td);
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate
4537c478bd9Sstevel@tonic-gate /*
4547c478bd9Sstevel@tonic-gate * Since we're about to start the read loop, we know our linked iob
4557c478bd9Sstevel@tonic-gate * is quiescent. We can now safely resize it to the latest term size.
4567c478bd9Sstevel@tonic-gate */
4577c478bd9Sstevel@tonic-gate if (td->tio_link != NULL)
4587c478bd9Sstevel@tonic-gate mdb_iob_resize(td->tio_link, td->tio_rows, td->tio_cols);
4597c478bd9Sstevel@tonic-gate
4607c478bd9Sstevel@tonic-gate td->tio_active = TRUE;
4617c478bd9Sstevel@tonic-gate
4623b6e0a59SMatt Amdur /*
4633b6e0a59SMatt Amdur * We may have had some error while in tab completion mode which sent us
4643b6e0a59SMatt Amdur * longjmping all over the place. If that's the case, come back here and
4653b6e0a59SMatt Amdur * make sure the flag is off.
4663b6e0a59SMatt Amdur */
4673b6e0a59SMatt Amdur td->tio_flags &= ~TIO_TAB;
4683b6e0a59SMatt Amdur
4697c478bd9Sstevel@tonic-gate do {
4707c478bd9Sstevel@tonic-gate char_loop:
4717c478bd9Sstevel@tonic-gate if ((c = mdb_iob_getc(td->tio_in)) == EOF) {
4727c478bd9Sstevel@tonic-gate td->tio_active = FALSE;
4737c478bd9Sstevel@tonic-gate goto out;
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate
4767c478bd9Sstevel@tonic-gate if (c == KEY_ESC && esc == FALSE) {
4777c478bd9Sstevel@tonic-gate esc = TRUE;
4787c478bd9Sstevel@tonic-gate goto char_loop;
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate
4817c478bd9Sstevel@tonic-gate if (esc) {
4827c478bd9Sstevel@tonic-gate esc = FALSE;
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate if (c == '[') {
4857c478bd9Sstevel@tonic-gate pad++;
4867c478bd9Sstevel@tonic-gate goto char_loop;
4877c478bd9Sstevel@tonic-gate }
4887c478bd9Sstevel@tonic-gate
4897c478bd9Sstevel@tonic-gate c = META(c);
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate
4927c478bd9Sstevel@tonic-gate if (pad) {
4937c478bd9Sstevel@tonic-gate pad = FALSE;
494892f67e4SJoshua M. Clulow
495892f67e4SJoshua M. Clulow if ((fkey = FKEY(c)) != 0) {
496892f67e4SJoshua M. Clulow /*
497892f67e4SJoshua M. Clulow * Some terminals send a multibyte control
498892f67e4SJoshua M. Clulow * sequence for particular function keys.
499892f67e4SJoshua M. Clulow * These sequences are of the form:
500892f67e4SJoshua M. Clulow *
501892f67e4SJoshua M. Clulow * ESC [ n ~
502892f67e4SJoshua M. Clulow *
503892f67e4SJoshua M. Clulow * where "n" is a numeric character from
504892f67e4SJoshua M. Clulow * '0' to '9'.
505892f67e4SJoshua M. Clulow */
506892f67e4SJoshua M. Clulow goto char_loop;
507892f67e4SJoshua M. Clulow }
508892f67e4SJoshua M. Clulow
509892f67e4SJoshua M. Clulow if ((c = KPAD(c)) == 0) {
510892f67e4SJoshua M. Clulow /*
511892f67e4SJoshua M. Clulow * This was not a valid keypad control
512892f67e4SJoshua M. Clulow * sequence.
513892f67e4SJoshua M. Clulow */
514892f67e4SJoshua M. Clulow goto char_loop;
515892f67e4SJoshua M. Clulow }
516892f67e4SJoshua M. Clulow }
517892f67e4SJoshua M. Clulow
518892f67e4SJoshua M. Clulow if (fkey != 0) {
519892f67e4SJoshua M. Clulow if (c == '~') {
520892f67e4SJoshua M. Clulow /*
521892f67e4SJoshua M. Clulow * This is a valid special function key
522892f67e4SJoshua M. Clulow * sequence. Use the value we stashed
523892f67e4SJoshua M. Clulow * earlier.
524892f67e4SJoshua M. Clulow */
525892f67e4SJoshua M. Clulow c = fkey;
526892f67e4SJoshua M. Clulow }
527892f67e4SJoshua M. Clulow
528892f67e4SJoshua M. Clulow fkey = 0;
5297c478bd9Sstevel@tonic-gate }
5307c478bd9Sstevel@tonic-gate
5317c478bd9Sstevel@tonic-gate len = td->tio_cmdbuf.cmd_buflen + td->tio_promptlen;
5327c478bd9Sstevel@tonic-gate
5337c478bd9Sstevel@tonic-gate td->tio_max_x = len % td->tio_cols;
5347c478bd9Sstevel@tonic-gate td->tio_max_y = len / td->tio_cols;
5357c478bd9Sstevel@tonic-gate
5367c478bd9Sstevel@tonic-gate } while ((s = (*td->tio_keymap[c])(td, c)) == NULL);
5377c478bd9Sstevel@tonic-gate
5387c478bd9Sstevel@tonic-gate td->tio_active = FALSE;
5397c478bd9Sstevel@tonic-gate mdb_iob_nl(td->tio_out);
5407c478bd9Sstevel@tonic-gate
5417c478bd9Sstevel@tonic-gate if ((rlen = strlen(s)) >= nbytes - 1)
5427c478bd9Sstevel@tonic-gate rlen = nbytes - 1;
5437c478bd9Sstevel@tonic-gate
5447c478bd9Sstevel@tonic-gate (void) strncpy(buf, s, rlen);
5457c478bd9Sstevel@tonic-gate ((char *)buf)[rlen++] = '\n';
5467c478bd9Sstevel@tonic-gate
5477c478bd9Sstevel@tonic-gate out:
5487c478bd9Sstevel@tonic-gate td->tio_rti_on = FALSE;
5497c478bd9Sstevel@tonic-gate if (termio_ctl(td->tio_io, TCSETSW, &td->tio_dtios) == -1)
5507c478bd9Sstevel@tonic-gate warn("failed to restore terminal attributes");
5517c478bd9Sstevel@tonic-gate
5527c478bd9Sstevel@tonic-gate return (rlen);
5537c478bd9Sstevel@tonic-gate }
5547c478bd9Sstevel@tonic-gate
5557c478bd9Sstevel@tonic-gate static ssize_t
termio_write(mdb_io_t * io,const void * buf,size_t nbytes)5567c478bd9Sstevel@tonic-gate termio_write(mdb_io_t *io, const void *buf, size_t nbytes)
5577c478bd9Sstevel@tonic-gate {
5587c478bd9Sstevel@tonic-gate termio_data_t *td = io->io_data;
5597c478bd9Sstevel@tonic-gate
5607c478bd9Sstevel@tonic-gate if (io->io_next != NULL)
5617c478bd9Sstevel@tonic-gate return (IOP_WRITE(io->io_next, buf, nbytes));
5627c478bd9Sstevel@tonic-gate
5637c478bd9Sstevel@tonic-gate return (IOP_WRITE(td->tio_out_io, buf, nbytes));
5647c478bd9Sstevel@tonic-gate }
5657c478bd9Sstevel@tonic-gate
5667c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5677c478bd9Sstevel@tonic-gate static off64_t
termio_seek(mdb_io_t * io,off64_t offset,int whence)5687c478bd9Sstevel@tonic-gate termio_seek(mdb_io_t *io, off64_t offset, int whence)
5697c478bd9Sstevel@tonic-gate {
5707c478bd9Sstevel@tonic-gate return (set_errno(ENOTSUP));
5717c478bd9Sstevel@tonic-gate }
5727c478bd9Sstevel@tonic-gate
5737c478bd9Sstevel@tonic-gate static int
termio_ctl(mdb_io_t * io,int req,void * arg)5747c478bd9Sstevel@tonic-gate termio_ctl(mdb_io_t *io, int req, void *arg)
5757c478bd9Sstevel@tonic-gate {
5767c478bd9Sstevel@tonic-gate termio_data_t *td = io->io_data;
5777c478bd9Sstevel@tonic-gate
5787c478bd9Sstevel@tonic-gate if (io->io_next != NULL)
5797c478bd9Sstevel@tonic-gate return (IOP_CTL(io->io_next, req, arg));
5807c478bd9Sstevel@tonic-gate
5817c478bd9Sstevel@tonic-gate if (req == MDB_IOC_CTTY) {
5827c478bd9Sstevel@tonic-gate bcopy(&td->tio_ptios, &td->tio_ctios, sizeof (struct termios));
5837c478bd9Sstevel@tonic-gate return (0);
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate
5867c478bd9Sstevel@tonic-gate return (IOP_CTL(td->tio_in_io, req, arg));
5877c478bd9Sstevel@tonic-gate }
5887c478bd9Sstevel@tonic-gate
5897c478bd9Sstevel@tonic-gate static void
termio_close(mdb_io_t * io)5907c478bd9Sstevel@tonic-gate termio_close(mdb_io_t *io)
5917c478bd9Sstevel@tonic-gate {
5927c478bd9Sstevel@tonic-gate termio_data_t *td = io->io_data;
5937c478bd9Sstevel@tonic-gate
594*30699046SRichard Lowe (void) mdb_signal_sethandler(SIGWINCH, MDB_SIG_DFL, NULL);
595*30699046SRichard Lowe (void) mdb_signal_sethandler(SIGTSTP, MDB_SIG_DFL, NULL);
5967c478bd9Sstevel@tonic-gate
5977c478bd9Sstevel@tonic-gate termio_suspend_tty(td, &td->tio_ptios);
5987c478bd9Sstevel@tonic-gate
5997c478bd9Sstevel@tonic-gate if (td->tio_attrs)
6007c478bd9Sstevel@tonic-gate mdb_free(td->tio_attrs, td->tio_attrslen);
6017c478bd9Sstevel@tonic-gate
6027c478bd9Sstevel@tonic-gate mdb_cmdbuf_destroy(&td->tio_cmdbuf);
6037c478bd9Sstevel@tonic-gate
6047c478bd9Sstevel@tonic-gate mdb_iob_destroy(td->tio_out);
6057c478bd9Sstevel@tonic-gate mdb_iob_destroy(td->tio_in);
6067c478bd9Sstevel@tonic-gate
6077c478bd9Sstevel@tonic-gate mdb_free(td, sizeof (termio_data_t));
6087c478bd9Sstevel@tonic-gate }
6097c478bd9Sstevel@tonic-gate
6107c478bd9Sstevel@tonic-gate static const char *
termio_name(mdb_io_t * io)6117c478bd9Sstevel@tonic-gate termio_name(mdb_io_t *io)
6127c478bd9Sstevel@tonic-gate {
6137c478bd9Sstevel@tonic-gate termio_data_t *td = io->io_data;
6147c478bd9Sstevel@tonic-gate
6157c478bd9Sstevel@tonic-gate if (io->io_next != NULL)
6167c478bd9Sstevel@tonic-gate return (IOP_NAME(io->io_next));
6177c478bd9Sstevel@tonic-gate
6187c478bd9Sstevel@tonic-gate return (IOP_NAME(td->tio_in_io));
6197c478bd9Sstevel@tonic-gate }
6207c478bd9Sstevel@tonic-gate
6217c478bd9Sstevel@tonic-gate static void
termio_link(mdb_io_t * io,mdb_iob_t * iob)6227c478bd9Sstevel@tonic-gate termio_link(mdb_io_t *io, mdb_iob_t *iob)
6237c478bd9Sstevel@tonic-gate {
6247c478bd9Sstevel@tonic-gate termio_data_t *td = io->io_data;
6257c478bd9Sstevel@tonic-gate
6267c478bd9Sstevel@tonic-gate if (io->io_next == NULL) {
6277c478bd9Sstevel@tonic-gate mdb_iob_resize(iob, td->tio_rows, td->tio_cols);
6287c478bd9Sstevel@tonic-gate td->tio_link = iob;
6297c478bd9Sstevel@tonic-gate } else
6307c478bd9Sstevel@tonic-gate IOP_LINK(io->io_next, iob);
6317c478bd9Sstevel@tonic-gate }
6327c478bd9Sstevel@tonic-gate
6337c478bd9Sstevel@tonic-gate static void
termio_unlink(mdb_io_t * io,mdb_iob_t * iob)6347c478bd9Sstevel@tonic-gate termio_unlink(mdb_io_t *io, mdb_iob_t *iob)
6357c478bd9Sstevel@tonic-gate {
6367c478bd9Sstevel@tonic-gate termio_data_t *td = io->io_data;
6377c478bd9Sstevel@tonic-gate
6387c478bd9Sstevel@tonic-gate if (io->io_next == NULL) {
6397c478bd9Sstevel@tonic-gate if (td->tio_link == iob)
6407c478bd9Sstevel@tonic-gate td->tio_link = NULL;
6417c478bd9Sstevel@tonic-gate } else
6427c478bd9Sstevel@tonic-gate IOP_UNLINK(io->io_next, iob);
6437c478bd9Sstevel@tonic-gate }
6447c478bd9Sstevel@tonic-gate
6457c478bd9Sstevel@tonic-gate static int
termio_setattr(mdb_io_t * io,int req,uint_t attrs)6467c478bd9Sstevel@tonic-gate termio_setattr(mdb_io_t *io, int req, uint_t attrs)
6477c478bd9Sstevel@tonic-gate {
6487c478bd9Sstevel@tonic-gate termio_data_t *td = io->io_data;
6497c478bd9Sstevel@tonic-gate
6507c478bd9Sstevel@tonic-gate if (io->io_next != NULL)
6517c478bd9Sstevel@tonic-gate return (IOP_SETATTR(io->io_next, req, attrs));
6527c478bd9Sstevel@tonic-gate
6537c478bd9Sstevel@tonic-gate if ((req != ATT_ON && req != ATT_OFF) || (attrs & ~ATT_ALL) != 0)
6547c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
6557c478bd9Sstevel@tonic-gate
6567c478bd9Sstevel@tonic-gate if (req == ATT_ON) {
6577c478bd9Sstevel@tonic-gate if (attrs & ATT_STANDOUT)
6587c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_smso.at_str, 1);
6597c478bd9Sstevel@tonic-gate if (attrs & ATT_UNDERLINE)
6607c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_smul.at_str, 1);
6617c478bd9Sstevel@tonic-gate if (attrs & ATT_REVERSE)
6627c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_rev.at_str, 1);
6637c478bd9Sstevel@tonic-gate if (attrs & ATT_BOLD)
6647c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_bold.at_str, 1);
6657c478bd9Sstevel@tonic-gate if (attrs & ATT_DIM)
6667c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_dim.at_str, 1);
6677c478bd9Sstevel@tonic-gate if (attrs & ATT_ALTCHARSET)
6687c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_smacs.at_str, 1);
6697c478bd9Sstevel@tonic-gate } else {
6707c478bd9Sstevel@tonic-gate if (attrs & ATT_STANDOUT)
6717c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_rmso.at_str, 1);
6727c478bd9Sstevel@tonic-gate if (attrs & ATT_UNDERLINE)
6737c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_rmul.at_str, 1);
6747c478bd9Sstevel@tonic-gate if (attrs & ATT_ALTCHARSET)
6757c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_rmacs.at_str, 1);
6767c478bd9Sstevel@tonic-gate if (attrs & (ATT_REVERSE | ATT_BOLD | ATT_DIM))
6777c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_sgr0.at_str, 1);
6787c478bd9Sstevel@tonic-gate }
6797c478bd9Sstevel@tonic-gate
6807c478bd9Sstevel@tonic-gate mdb_iob_flush(td->tio_out);
6817c478bd9Sstevel@tonic-gate return (0);
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate
6847c478bd9Sstevel@tonic-gate /*
6857c478bd9Sstevel@tonic-gate * Issue a warning message if the given warning flag is clear. Then set the
6867c478bd9Sstevel@tonic-gate * flag bit so that we do not issue multiple instances of the same warning.
6877c478bd9Sstevel@tonic-gate */
6887c478bd9Sstevel@tonic-gate static void
termio_warn(termio_data_t * td,uint_t flag,const char * format,...)6897c478bd9Sstevel@tonic-gate termio_warn(termio_data_t *td, uint_t flag, const char *format, ...)
6907c478bd9Sstevel@tonic-gate {
6917c478bd9Sstevel@tonic-gate if (!(td->tio_flags & flag)) {
6927c478bd9Sstevel@tonic-gate va_list alist;
6937c478bd9Sstevel@tonic-gate
6947c478bd9Sstevel@tonic-gate va_start(alist, format);
6957c478bd9Sstevel@tonic-gate vwarn(format, alist);
6967c478bd9Sstevel@tonic-gate va_end(alist);
6977c478bd9Sstevel@tonic-gate
6987c478bd9Sstevel@tonic-gate td->tio_flags |= flag;
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate
7027c478bd9Sstevel@tonic-gate /*
7037c478bd9Sstevel@tonic-gate * Restore the terminal to its previous state before relinquishing control of
7047c478bd9Sstevel@tonic-gate * it to the shell (on a SIGTSTP) or the victim process (on a continue). If
7057c478bd9Sstevel@tonic-gate * we need to change the foreground process group, we must temporarily ignore
7067c478bd9Sstevel@tonic-gate * SIGTTOU because TIOCSPGRP could trigger it.
7077c478bd9Sstevel@tonic-gate */
7087c478bd9Sstevel@tonic-gate static void
termio_suspend_tty(termio_data_t * td,struct termios * iosp)7097c478bd9Sstevel@tonic-gate termio_suspend_tty(termio_data_t *td, struct termios *iosp)
7107c478bd9Sstevel@tonic-gate {
7117c478bd9Sstevel@tonic-gate if (td->tio_suspended++ != 0)
7127c478bd9Sstevel@tonic-gate return; /* already suspended; do not restore state */
7137c478bd9Sstevel@tonic-gate
7147c478bd9Sstevel@tonic-gate if (td->tio_flags & TIO_XTERM)
7157c478bd9Sstevel@tonic-gate termio_tput(td, TI_DECRES(TI_COLENAB), 1);
7167c478bd9Sstevel@tonic-gate
7177c478bd9Sstevel@tonic-gate if (td->tio_flags & TIO_USECUP)
7187c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_rmcup.at_str, 1);
7197c478bd9Sstevel@tonic-gate
7207c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_sgr0.at_str, 1);
7217c478bd9Sstevel@tonic-gate mdb_iob_flush(td->tio_out);
7227c478bd9Sstevel@tonic-gate
7237c478bd9Sstevel@tonic-gate if (termio_ctl(td->tio_io, TCSETSW, iosp) == -1)
7247c478bd9Sstevel@tonic-gate warn("failed to restore terminal attributes");
7257c478bd9Sstevel@tonic-gate
7267c478bd9Sstevel@tonic-gate if (td->tio_opgid > 0 && td->tio_opgid != mdb.m_pgid) {
7277c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_CMDBUF, "fg pgid=%d\n", (int)td->tio_opgid);
728*30699046SRichard Lowe (void) mdb_signal_sethandler(SIGTTOU, MDB_SIG_IGN, NULL);
7297c478bd9Sstevel@tonic-gate (void) termio_ctl(td->tio_io, TIOCSPGRP, &td->tio_opgid);
730*30699046SRichard Lowe (void) mdb_signal_sethandler(SIGTTOU, MDB_SIG_DFL, NULL);
7317c478bd9Sstevel@tonic-gate }
7327c478bd9Sstevel@tonic-gate }
7337c478bd9Sstevel@tonic-gate
7347c478bd9Sstevel@tonic-gate /*
7357c478bd9Sstevel@tonic-gate * Resume the debugger's terminal state. We first save the existing terminal
7367c478bd9Sstevel@tonic-gate * state so we can restore it later, and then install our own state. We
7377c478bd9Sstevel@tonic-gate * derive our state dynamically from the existing terminal state so that we
7387c478bd9Sstevel@tonic-gate * always reflect the latest modifications made by the user with stty(1).
7397c478bd9Sstevel@tonic-gate */
7407c478bd9Sstevel@tonic-gate static void
termio_resume_tty(termio_data_t * td,struct termios * iosp)7417c478bd9Sstevel@tonic-gate termio_resume_tty(termio_data_t *td, struct termios *iosp)
7427c478bd9Sstevel@tonic-gate {
7437c478bd9Sstevel@tonic-gate /*
7447c478bd9Sstevel@tonic-gate * We use this table of bauds to convert the baud constant returned by
7457c478bd9Sstevel@tonic-gate * the terminal code to a baud rate in characters per second. The
7467c478bd9Sstevel@tonic-gate * values are in the order of the B* speed defines in <sys/termios.h>.
7477c478bd9Sstevel@tonic-gate * We then compute tio_usecpc (microseconds-per-char) in order to
7487c478bd9Sstevel@tonic-gate * determine how many pad characters need to be issued at the current
7497c478bd9Sstevel@tonic-gate * terminal speed to delay for a given number of microseconds. For
7507c478bd9Sstevel@tonic-gate * example, at 300 baud (B300 = 7), we look up baud[7] = 300, and then
7517c478bd9Sstevel@tonic-gate * compute usecpc as MICROSEC / 300 = 3333 microseconds per character.
7527c478bd9Sstevel@tonic-gate */
7537c478bd9Sstevel@tonic-gate static const uint_t baud[] = {
7547c478bd9Sstevel@tonic-gate 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
7557c478bd9Sstevel@tonic-gate 1800, 2400, 4800, 9600, 19200, 38400, 57600,
756d9c3e05cSJoshua M. Clulow 76800, 115200, 153600, 230400, 307200, 460800, 921600,
757d9c3e05cSJoshua M. Clulow 1000000, 1152000, 1500000, 2000000, 2500000, 3000000,
758d9c3e05cSJoshua M. Clulow 3500000, 4000000
7597c478bd9Sstevel@tonic-gate };
7607c478bd9Sstevel@tonic-gate
7617c478bd9Sstevel@tonic-gate struct termios *ntios;
7627c478bd9Sstevel@tonic-gate struct winsize winsz;
7637c478bd9Sstevel@tonic-gate uint_t speed;
7647c478bd9Sstevel@tonic-gate
7657c478bd9Sstevel@tonic-gate if (td->tio_suspended == 0)
7667c478bd9Sstevel@tonic-gate fail("termio_resume called without matching termio_suspend\n");
7677c478bd9Sstevel@tonic-gate
7687c478bd9Sstevel@tonic-gate if (--td->tio_suspended != 0)
7697c478bd9Sstevel@tonic-gate return; /* nested suspends; do not resume yet */
7707c478bd9Sstevel@tonic-gate
7717c478bd9Sstevel@tonic-gate td->tio_opgid = -1; /* set to invalid pgid in case TIOCPGRP fails */
7727c478bd9Sstevel@tonic-gate (void) termio_ctl(td->tio_io, TIOCGPGRP, &td->tio_opgid);
7737c478bd9Sstevel@tonic-gate
7747c478bd9Sstevel@tonic-gate /*
7757c478bd9Sstevel@tonic-gate * If the foreground process group does not include the debugger, reset
7767c478bd9Sstevel@tonic-gate * the foreground process group so we are in control of the terminal.
7777c478bd9Sstevel@tonic-gate * We temporarily ignore TTOU because TIOCSPGRP could trigger it.
7787c478bd9Sstevel@tonic-gate */
7797c478bd9Sstevel@tonic-gate if (td->tio_opgid != mdb.m_pgid) {
780*30699046SRichard Lowe (void) mdb_signal_sethandler(SIGTTOU, MDB_SIG_IGN, NULL);
7817c478bd9Sstevel@tonic-gate (void) termio_ctl(td->tio_io, TIOCSPGRP, &mdb.m_pgid);
782*30699046SRichard Lowe (void) mdb_signal_sethandler(SIGTTOU, MDB_SIG_DFL, NULL);
7837c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_CMDBUF, "fg pgid=%d\n", (int)mdb.m_pgid);
7847c478bd9Sstevel@tonic-gate }
7857c478bd9Sstevel@tonic-gate
7867c478bd9Sstevel@tonic-gate /*
7877c478bd9Sstevel@tonic-gate * Read the current set of terminal attributes, and save them in iosp
7887c478bd9Sstevel@tonic-gate * so we can restore them later. Then derive rtios, dtios, and winsz.
7897c478bd9Sstevel@tonic-gate */
7907c478bd9Sstevel@tonic-gate if (termio_ctl(td->tio_io, TCGETS, iosp) < 0)
7917c478bd9Sstevel@tonic-gate warn("failed to get terminal attributes");
7927c478bd9Sstevel@tonic-gate
7937c478bd9Sstevel@tonic-gate if (termio_ctl(td->tio_io, TIOCGWINSZ, &winsz) == 0) {
7947c478bd9Sstevel@tonic-gate if (winsz.ws_row != 0)
7957c478bd9Sstevel@tonic-gate td->tio_rows = (size_t)winsz.ws_row;
7967c478bd9Sstevel@tonic-gate if (winsz.ws_col != 0)
7977c478bd9Sstevel@tonic-gate td->tio_cols = (size_t)winsz.ws_col;
7987c478bd9Sstevel@tonic-gate }
7997c478bd9Sstevel@tonic-gate
8007c478bd9Sstevel@tonic-gate mdb_iob_resize(td->tio_out, td->tio_rows, td->tio_cols);
8017c478bd9Sstevel@tonic-gate
8027c478bd9Sstevel@tonic-gate td->tio_intr = td->tio_ptios.c_cc[VINTR];
8037c478bd9Sstevel@tonic-gate td->tio_quit = td->tio_ptios.c_cc[VQUIT];
8047c478bd9Sstevel@tonic-gate td->tio_erase = td->tio_ptios.c_cc[VERASE];
8057c478bd9Sstevel@tonic-gate td->tio_werase = td->tio_ptios.c_cc[VWERASE];
8067c478bd9Sstevel@tonic-gate td->tio_kill = td->tio_ptios.c_cc[VKILL];
8077c478bd9Sstevel@tonic-gate td->tio_eof = td->tio_ptios.c_cc[VEOF];
8087c478bd9Sstevel@tonic-gate td->tio_susp = td->tio_ptios.c_cc[VSUSP];
8097c478bd9Sstevel@tonic-gate
8107c478bd9Sstevel@tonic-gate bcopy(&td->tio_ptios, &td->tio_rtios, sizeof (struct termios));
8117c478bd9Sstevel@tonic-gate td->tio_rtios.c_iflag &= ~(ISTRIP | INPCK | ICRNL | INLCR | IUCLC);
8127c478bd9Sstevel@tonic-gate td->tio_rtios.c_oflag &= ~(OCRNL | ONLRET);
8137c478bd9Sstevel@tonic-gate td->tio_rtios.c_oflag |= ONLCR;
8147c478bd9Sstevel@tonic-gate td->tio_rtios.c_lflag &= ~(ISIG | ICANON | ECHO);
8157c478bd9Sstevel@tonic-gate td->tio_rtios.c_cflag |= CS8;
8167c478bd9Sstevel@tonic-gate td->tio_rtios.c_cc[VTIME] = 0;
8177c478bd9Sstevel@tonic-gate td->tio_rtios.c_cc[VMIN] = 1;
8187c478bd9Sstevel@tonic-gate
8197c478bd9Sstevel@tonic-gate bcopy(&td->tio_ptios, &td->tio_dtios, sizeof (struct termios));
8207c478bd9Sstevel@tonic-gate td->tio_dtios.c_oflag &= ~(OCRNL | ONLRET);
8217c478bd9Sstevel@tonic-gate td->tio_dtios.c_oflag |= ONLCR;
8227c478bd9Sstevel@tonic-gate td->tio_dtios.c_lflag |= ISIG | ICANON | ECHO;
8237c478bd9Sstevel@tonic-gate
8247c478bd9Sstevel@tonic-gate /*
8257c478bd9Sstevel@tonic-gate * Select the appropriate modified settings to restore based on our
8267c478bd9Sstevel@tonic-gate * current state, and then install them.
8277c478bd9Sstevel@tonic-gate */
8287c478bd9Sstevel@tonic-gate if (td->tio_rti_on)
8297c478bd9Sstevel@tonic-gate ntios = &td->tio_rtios;
8307c478bd9Sstevel@tonic-gate else
8317c478bd9Sstevel@tonic-gate ntios = &td->tio_dtios;
8327c478bd9Sstevel@tonic-gate
8337c478bd9Sstevel@tonic-gate if (termio_ctl(td->tio_io, TCSETSW, ntios) < 0)
8347c478bd9Sstevel@tonic-gate warn("failed to reset terminal attributes");
8357c478bd9Sstevel@tonic-gate
8367c478bd9Sstevel@tonic-gate /*
837bbf21555SRichard Lowe * Compute the terminal speed as described in termio(4I), and then
8387c478bd9Sstevel@tonic-gate * look up the corresponding microseconds-per-char in our table.
8397c478bd9Sstevel@tonic-gate */
8407c478bd9Sstevel@tonic-gate if (ntios->c_cflag & CBAUDEXT)
8417c478bd9Sstevel@tonic-gate speed = (ntios->c_cflag & CBAUD) + CBAUD + 1;
8427c478bd9Sstevel@tonic-gate else
8437c478bd9Sstevel@tonic-gate speed = (ntios->c_cflag & CBAUD);
8447c478bd9Sstevel@tonic-gate
8457c478bd9Sstevel@tonic-gate if (speed >= sizeof (baud) / sizeof (baud[0])) {
8467c478bd9Sstevel@tonic-gate termio_warn(td, TIO_TTYWARN, "invalid speed %u -- assuming "
8477c478bd9Sstevel@tonic-gate "9600 baud\n", speed);
8487c478bd9Sstevel@tonic-gate speed = B9600;
8497c478bd9Sstevel@tonic-gate }
8507c478bd9Sstevel@tonic-gate
8517c478bd9Sstevel@tonic-gate td->tio_baud = baud[speed];
8527c478bd9Sstevel@tonic-gate td->tio_usecpc = MICROSEC / td->tio_baud;
8537c478bd9Sstevel@tonic-gate
8547c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_CMDBUF, "speed = %u baud (%u usec / char), "
8557c478bd9Sstevel@tonic-gate "putp = %s\n", td->tio_baud, td->tio_usecpc,
8567c478bd9Sstevel@tonic-gate td->tio_putp == &termio_puts ? "fast" : "slow");
8577c478bd9Sstevel@tonic-gate
8587c478bd9Sstevel@tonic-gate /*
8597c478bd9Sstevel@tonic-gate * Send the necessary terminal initialization sequences to enable
8607c478bd9Sstevel@tonic-gate * enable cursor positioning. Clear the screen afterward if possible.
8617c478bd9Sstevel@tonic-gate */
8627c478bd9Sstevel@tonic-gate if (td->tio_flags & TIO_USECUP) {
8637c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_smcup.at_str, 1);
8647c478bd9Sstevel@tonic-gate if (td->tio_info.ti_clear.at_str) {
8657c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_clear.at_str, 1);
8667c478bd9Sstevel@tonic-gate td->tio_x = td->tio_y = 0;
8677c478bd9Sstevel@tonic-gate }
8687c478bd9Sstevel@tonic-gate }
8697c478bd9Sstevel@tonic-gate
8707c478bd9Sstevel@tonic-gate /*
8717c478bd9Sstevel@tonic-gate * If the terminal is xterm-compatible, enable column mode switching.
8727c478bd9Sstevel@tonic-gate * Save the previous value in the terminal so we can restore it.
8737c478bd9Sstevel@tonic-gate */
8747c478bd9Sstevel@tonic-gate if (td->tio_flags & TIO_XTERM) {
8757c478bd9Sstevel@tonic-gate termio_tput(td, TI_DECSAV(TI_COLENAB), 1);
8767c478bd9Sstevel@tonic-gate termio_tput(td, TI_DECSET(TI_COLENAB), 1);
8777c478bd9Sstevel@tonic-gate }
8787c478bd9Sstevel@tonic-gate
8797c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_cnorm.at_str, 1); /* cursor visible */
8807c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_enacs.at_str, 1); /* alt char set */
8817c478bd9Sstevel@tonic-gate
882448027ebSBryan Cantrill /*
883448027ebSBryan Cantrill * If the terminal is automargin-capable and we have an initialization
884448027ebSBryan Cantrill * sequence to enable automargins, we must send it now. Note that
885448027ebSBryan Cantrill * we don't have a way of querying this mode and restoring it; if
886448027ebSBryan Cantrill * we are fighting with (say) a target that is depending on automargin
887448027ebSBryan Cantrill * being turned off, it will lose.
888448027ebSBryan Cantrill */
889448027ebSBryan Cantrill if ((td->tio_flags & TIO_AUTOWRAP) &&
890448027ebSBryan Cantrill td->tio_info.ti_smam.at_str != NULL) {
891448027ebSBryan Cantrill termio_tput(td, td->tio_info.ti_smam.at_str, 1);
892448027ebSBryan Cantrill }
893448027ebSBryan Cantrill
8947c478bd9Sstevel@tonic-gate mdb_iob_flush(td->tio_out);
8957c478bd9Sstevel@tonic-gate }
8967c478bd9Sstevel@tonic-gate
8977c478bd9Sstevel@tonic-gate static void
termio_suspend(mdb_io_t * io)8987c478bd9Sstevel@tonic-gate termio_suspend(mdb_io_t *io)
8997c478bd9Sstevel@tonic-gate {
9007c478bd9Sstevel@tonic-gate termio_data_t *td = io->io_data;
9017c478bd9Sstevel@tonic-gate termio_suspend_tty(td, &td->tio_ctios);
9027c478bd9Sstevel@tonic-gate }
9037c478bd9Sstevel@tonic-gate
9047c478bd9Sstevel@tonic-gate static void
termio_resume(mdb_io_t * io)9057c478bd9Sstevel@tonic-gate termio_resume(mdb_io_t *io)
9067c478bd9Sstevel@tonic-gate {
9077c478bd9Sstevel@tonic-gate termio_data_t *td = io->io_data;
9087c478bd9Sstevel@tonic-gate termio_resume_tty(td, &td->tio_ctios);
9097c478bd9Sstevel@tonic-gate }
9107c478bd9Sstevel@tonic-gate
9117c478bd9Sstevel@tonic-gate /*
9127c478bd9Sstevel@tonic-gate * Delay for the specified number of microseconds by sending the pad character
9137c478bd9Sstevel@tonic-gate * to the terminal. We round up by half a frame and then divide by the usecs
9147c478bd9Sstevel@tonic-gate * per character to determine the number of pad characters to send.
9157c478bd9Sstevel@tonic-gate */
9167c478bd9Sstevel@tonic-gate static void
termio_delay(termio_data_t * td,uint_t usec)9177c478bd9Sstevel@tonic-gate termio_delay(termio_data_t *td, uint_t usec)
9187c478bd9Sstevel@tonic-gate {
9197c478bd9Sstevel@tonic-gate char pad = td->tio_info.ti_pad.at_str[0];
9207c478bd9Sstevel@tonic-gate uint_t usecpc = td->tio_usecpc;
9217c478bd9Sstevel@tonic-gate
9227c478bd9Sstevel@tonic-gate for (usec = (usec + usecpc / 2) / usecpc; usec != 0; usec--) {
9237c478bd9Sstevel@tonic-gate mdb_iob_putc(td->tio_out, pad);
9247c478bd9Sstevel@tonic-gate mdb_iob_flush(td->tio_out);
9257c478bd9Sstevel@tonic-gate }
9267c478bd9Sstevel@tonic-gate }
9277c478bd9Sstevel@tonic-gate
9287c478bd9Sstevel@tonic-gate /*
929bbf21555SRichard Lowe * Parse the terminfo(5) padding sequence "$<...>" and delay for the specified
9307c478bd9Sstevel@tonic-gate * amount of time by sending pad characters to the terminal.
9317c478bd9Sstevel@tonic-gate */
9327c478bd9Sstevel@tonic-gate static const char *
termio_pad(termio_data_t * td,const char * s,uint_t lines)9337c478bd9Sstevel@tonic-gate termio_pad(termio_data_t *td, const char *s, uint_t lines)
9347c478bd9Sstevel@tonic-gate {
9357c478bd9Sstevel@tonic-gate int xon = td->tio_info.ti_xon.at_val;
9367c478bd9Sstevel@tonic-gate int pb = td->tio_info.ti_pb.at_val;
9377c478bd9Sstevel@tonic-gate
9387c478bd9Sstevel@tonic-gate const char *p = s;
9397c478bd9Sstevel@tonic-gate uint_t usec = 0;
9407c478bd9Sstevel@tonic-gate
9417c478bd9Sstevel@tonic-gate /*
9427c478bd9Sstevel@tonic-gate * The initial string is a number of milliseconds, followed by an
9437c478bd9Sstevel@tonic-gate * optional decimal point and number of tenths of milliseconds.
9447c478bd9Sstevel@tonic-gate * We convert this to microseconds for greater accuracy. Only a single
9457c478bd9Sstevel@tonic-gate * digit is permitted after the decimal point; we ignore any others.
9467c478bd9Sstevel@tonic-gate */
9477c478bd9Sstevel@tonic-gate while (*p >= '0' && *p <= '9')
9487c478bd9Sstevel@tonic-gate usec = usec * 10 + *p++ - '0';
9497c478bd9Sstevel@tonic-gate
9507c478bd9Sstevel@tonic-gate usec *= 1000; /* convert msecs to usecs */
9517c478bd9Sstevel@tonic-gate
9527c478bd9Sstevel@tonic-gate if (*p == '.') {
9537c478bd9Sstevel@tonic-gate if (p[1] >= '0' && p[1] <= '9')
9547c478bd9Sstevel@tonic-gate usec += (p[1] - '0') * 100;
9557c478bd9Sstevel@tonic-gate for (p++; *p >= '0' && *p <= '9'; p++)
9567c478bd9Sstevel@tonic-gate continue;
9577c478bd9Sstevel@tonic-gate }
9587c478bd9Sstevel@tonic-gate
9597c478bd9Sstevel@tonic-gate /*
9607c478bd9Sstevel@tonic-gate * Following the time delay specifier,
9617c478bd9Sstevel@tonic-gate *
9627c478bd9Sstevel@tonic-gate * 1. An optional "/" indicates that the delay should be done
9637c478bd9Sstevel@tonic-gate * regardless of the value of the terminal's xon property,
9647c478bd9Sstevel@tonic-gate * 2. An optional "*" indicates that the delay is proportional to the
9657c478bd9Sstevel@tonic-gate * count of affected lines, and
9667c478bd9Sstevel@tonic-gate * 3. A mandatory ">" terminates the sequence.
9677c478bd9Sstevel@tonic-gate *
9687c478bd9Sstevel@tonic-gate * If we encounter any other characters, we assume that we found "$<"
9697c478bd9Sstevel@tonic-gate * accidentally embedded in another sequence, so we just output "$".
9707c478bd9Sstevel@tonic-gate */
9717c478bd9Sstevel@tonic-gate for (;;) {
9727c478bd9Sstevel@tonic-gate switch (*p++) {
9737c478bd9Sstevel@tonic-gate case '/':
9747c478bd9Sstevel@tonic-gate xon = FALSE;
9757c478bd9Sstevel@tonic-gate continue;
9767c478bd9Sstevel@tonic-gate case '*':
9777c478bd9Sstevel@tonic-gate usec *= lines;
9787c478bd9Sstevel@tonic-gate continue;
9797c478bd9Sstevel@tonic-gate case '>':
9807c478bd9Sstevel@tonic-gate if (xon == FALSE && usec != 0 && td->tio_baud >= pb)
9817c478bd9Sstevel@tonic-gate termio_delay(td, usec);
9827c478bd9Sstevel@tonic-gate return (p);
9837c478bd9Sstevel@tonic-gate default:
9847c478bd9Sstevel@tonic-gate mdb_iob_putc(td->tio_out, *s);
9857c478bd9Sstevel@tonic-gate return (s + 1);
9867c478bd9Sstevel@tonic-gate }
9877c478bd9Sstevel@tonic-gate }
9887c478bd9Sstevel@tonic-gate }
9897c478bd9Sstevel@tonic-gate
9907c478bd9Sstevel@tonic-gate /*
9917c478bd9Sstevel@tonic-gate * termio_tput() subroutine for terminals that require padding. We look ahead
9927c478bd9Sstevel@tonic-gate * for "$<>" sequences, and call termio_pad() to process them; all other chars
9937c478bd9Sstevel@tonic-gate * are output directly to the underlying device and then flushed at the end.
9947c478bd9Sstevel@tonic-gate */
9957c478bd9Sstevel@tonic-gate static void
termio_putp(termio_data_t * td,const char * s,uint_t lines)9967c478bd9Sstevel@tonic-gate termio_putp(termio_data_t *td, const char *s, uint_t lines)
9977c478bd9Sstevel@tonic-gate {
9987c478bd9Sstevel@tonic-gate while (s[0] != '\0') {
9997c478bd9Sstevel@tonic-gate if (s[0] == '$' && s[1] == '<')
10007c478bd9Sstevel@tonic-gate s = termio_pad(td, s + 2, lines);
10017c478bd9Sstevel@tonic-gate else
10027c478bd9Sstevel@tonic-gate mdb_iob_putc(td->tio_out, *s++);
10037c478bd9Sstevel@tonic-gate }
10047c478bd9Sstevel@tonic-gate
10057c478bd9Sstevel@tonic-gate mdb_iob_flush(td->tio_out);
10067c478bd9Sstevel@tonic-gate }
10077c478bd9Sstevel@tonic-gate
10087c478bd9Sstevel@tonic-gate /*
10097c478bd9Sstevel@tonic-gate * termio_tput() subroutine for terminals that do not require padding. We
10107c478bd9Sstevel@tonic-gate * simply output the string to the underlying i/o buffer; we let the caller
10117c478bd9Sstevel@tonic-gate * take care of flushing so that multiple sequences can be concatenated.
10127c478bd9Sstevel@tonic-gate */
10137c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10147c478bd9Sstevel@tonic-gate static void
termio_puts(termio_data_t * td,const char * s,uint_t lines)10157c478bd9Sstevel@tonic-gate termio_puts(termio_data_t *td, const char *s, uint_t lines)
10167c478bd9Sstevel@tonic-gate {
10177c478bd9Sstevel@tonic-gate mdb_iob_puts(td->tio_out, s);
10187c478bd9Sstevel@tonic-gate }
10197c478bd9Sstevel@tonic-gate
10207c478bd9Sstevel@tonic-gate /*
10217c478bd9Sstevel@tonic-gate * Print a padded escape sequence string to the terminal. The caller specifies
10227c478bd9Sstevel@tonic-gate * the string 's' and a count of the affected lines. If the string contains an
1023bbf21555SRichard Lowe * embedded delay sequence delimited by "$<>" (see terminfo(5)), appropriate
10247c478bd9Sstevel@tonic-gate * padding will be included in the output. We determine whether or not padding
10257c478bd9Sstevel@tonic-gate * is required during initialization, and set tio_putp to the proper subroutine.
10267c478bd9Sstevel@tonic-gate */
10277c478bd9Sstevel@tonic-gate static void
termio_tput(termio_data_t * td,const char * s,uint_t lines)10287c478bd9Sstevel@tonic-gate termio_tput(termio_data_t *td, const char *s, uint_t lines)
10297c478bd9Sstevel@tonic-gate {
10307c478bd9Sstevel@tonic-gate if (s != NULL)
10317c478bd9Sstevel@tonic-gate td->tio_putp(td, s, lines);
10327c478bd9Sstevel@tonic-gate }
10337c478bd9Sstevel@tonic-gate
10347c478bd9Sstevel@tonic-gate static void
termio_addch(termio_data_t * td,char c,size_t width)10357c478bd9Sstevel@tonic-gate termio_addch(termio_data_t *td, char c, size_t width)
10367c478bd9Sstevel@tonic-gate {
10377c478bd9Sstevel@tonic-gate if (width == 1) {
10387c478bd9Sstevel@tonic-gate mdb_iob_putc(td->tio_out, c);
10397c478bd9Sstevel@tonic-gate td->tio_x++;
10407c478bd9Sstevel@tonic-gate
10417c478bd9Sstevel@tonic-gate if (td->tio_x >= td->tio_cols) {
10427c478bd9Sstevel@tonic-gate if (!(td->tio_flags & TIO_AUTOWRAP))
10437c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_nel.at_str, 1);
10447c478bd9Sstevel@tonic-gate td->tio_x = 0;
10457c478bd9Sstevel@tonic-gate td->tio_y++;
10467c478bd9Sstevel@tonic-gate }
10477c478bd9Sstevel@tonic-gate
10487c478bd9Sstevel@tonic-gate mdb_iob_flush(td->tio_out);
10497c478bd9Sstevel@tonic-gate } else
10507c478bd9Sstevel@tonic-gate termio_redraw(td);
10517c478bd9Sstevel@tonic-gate }
10527c478bd9Sstevel@tonic-gate
10537c478bd9Sstevel@tonic-gate static void
termio_insch(termio_data_t * td,char c,size_t width)10547c478bd9Sstevel@tonic-gate termio_insch(termio_data_t *td, char c, size_t width)
10557c478bd9Sstevel@tonic-gate {
10567c478bd9Sstevel@tonic-gate if (width == 1 && (td->tio_flags & TIO_INSERT) &&
10577c478bd9Sstevel@tonic-gate td->tio_y == td->tio_max_y) {
10587c478bd9Sstevel@tonic-gate
10597c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_smir.at_str, 1);
10607c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_ich1.at_str, 1);
10617c478bd9Sstevel@tonic-gate
10627c478bd9Sstevel@tonic-gate mdb_iob_putc(td->tio_out, c);
10637c478bd9Sstevel@tonic-gate td->tio_x++;
10647c478bd9Sstevel@tonic-gate
10657c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_ip.at_str, 1);
10667c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_rmir.at_str, 1);
10677c478bd9Sstevel@tonic-gate
10687c478bd9Sstevel@tonic-gate if (td->tio_x >= td->tio_cols) {
10697c478bd9Sstevel@tonic-gate if (!(td->tio_flags & TIO_AUTOWRAP))
10707c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_nel.at_str, 1);
10717c478bd9Sstevel@tonic-gate td->tio_x = 0;
10727c478bd9Sstevel@tonic-gate td->tio_y++;
10737c478bd9Sstevel@tonic-gate }
10747c478bd9Sstevel@tonic-gate
10757c478bd9Sstevel@tonic-gate mdb_iob_flush(td->tio_out);
10767c478bd9Sstevel@tonic-gate } else
10777c478bd9Sstevel@tonic-gate termio_redraw(td);
10787c478bd9Sstevel@tonic-gate }
10797c478bd9Sstevel@tonic-gate
10807c478bd9Sstevel@tonic-gate static void
termio_mvcur(termio_data_t * td)10817c478bd9Sstevel@tonic-gate termio_mvcur(termio_data_t *td)
10827c478bd9Sstevel@tonic-gate {
10837c478bd9Sstevel@tonic-gate size_t tipos = td->tio_cmdbuf.cmd_bufidx + td->tio_promptlen;
10847c478bd9Sstevel@tonic-gate size_t dst_x = tipos % td->tio_cols;
10857c478bd9Sstevel@tonic-gate size_t dst_y = tipos / td->tio_cols;
10867c478bd9Sstevel@tonic-gate
10877c478bd9Sstevel@tonic-gate const char *str;
10887c478bd9Sstevel@tonic-gate size_t cnt, i;
10897c478bd9Sstevel@tonic-gate
10907c478bd9Sstevel@tonic-gate if (td->tio_y != dst_y) {
10917c478bd9Sstevel@tonic-gate if (td->tio_y < dst_y) {
10927c478bd9Sstevel@tonic-gate str = td->tio_info.ti_cud1.at_str;
10937c478bd9Sstevel@tonic-gate cnt = dst_y - td->tio_y;
10947c478bd9Sstevel@tonic-gate td->tio_x = 0; /* Note: cud1 moves cursor to column 0 */
10957c478bd9Sstevel@tonic-gate } else {
10967c478bd9Sstevel@tonic-gate str = td->tio_info.ti_cuu1.at_str;
10977c478bd9Sstevel@tonic-gate cnt = td->tio_y - dst_y;
10987c478bd9Sstevel@tonic-gate }
10997c478bd9Sstevel@tonic-gate
11007c478bd9Sstevel@tonic-gate for (i = 0; i < cnt; i++)
11017c478bd9Sstevel@tonic-gate termio_tput(td, str, 1);
11027c478bd9Sstevel@tonic-gate
11037c478bd9Sstevel@tonic-gate mdb_iob_flush(td->tio_out);
11047c478bd9Sstevel@tonic-gate td->tio_y = dst_y;
11057c478bd9Sstevel@tonic-gate }
11067c478bd9Sstevel@tonic-gate
11077c478bd9Sstevel@tonic-gate if (td->tio_x != dst_x) {
11087c478bd9Sstevel@tonic-gate if (td->tio_x < dst_x) {
11097c478bd9Sstevel@tonic-gate str = td->tio_info.ti_cuf1.at_str;
11107c478bd9Sstevel@tonic-gate cnt = dst_x - td->tio_x;
11117c478bd9Sstevel@tonic-gate } else {
11127c478bd9Sstevel@tonic-gate str = td->tio_info.ti_cub1.at_str;
11137c478bd9Sstevel@tonic-gate cnt = td->tio_x - dst_x;
11147c478bd9Sstevel@tonic-gate }
11157c478bd9Sstevel@tonic-gate
11167c478bd9Sstevel@tonic-gate for (i = 0; i < cnt; i++)
11177c478bd9Sstevel@tonic-gate termio_tput(td, str, 1);
11187c478bd9Sstevel@tonic-gate
11197c478bd9Sstevel@tonic-gate mdb_iob_flush(td->tio_out);
11207c478bd9Sstevel@tonic-gate td->tio_x = dst_x;
11217c478bd9Sstevel@tonic-gate }
11227c478bd9Sstevel@tonic-gate }
11237c478bd9Sstevel@tonic-gate
11247c478bd9Sstevel@tonic-gate static void
termio_backleft(termio_data_t * td)11257c478bd9Sstevel@tonic-gate termio_backleft(termio_data_t *td)
11267c478bd9Sstevel@tonic-gate {
11277c478bd9Sstevel@tonic-gate size_t i;
11287c478bd9Sstevel@tonic-gate
11297c478bd9Sstevel@tonic-gate if (td->tio_flags & TIO_BACKLEFT)
11307c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_cub1.at_str, 1);
11317c478bd9Sstevel@tonic-gate else {
11327c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_cuu1.at_str, 1);
11337c478bd9Sstevel@tonic-gate for (i = 0; i < td->tio_cols - 1; i++)
11347c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_cuf1.at_str, 1);
11357c478bd9Sstevel@tonic-gate }
11367c478bd9Sstevel@tonic-gate }
11377c478bd9Sstevel@tonic-gate
11387c478bd9Sstevel@tonic-gate static void
termio_bspch(termio_data_t * td)11397c478bd9Sstevel@tonic-gate termio_bspch(termio_data_t *td)
11407c478bd9Sstevel@tonic-gate {
11417c478bd9Sstevel@tonic-gate if (td->tio_x == 0) {
1142448027ebSBryan Cantrill /*
1143448027ebSBryan Cantrill * If TIO_LAZYWRAP is set, we are regrettably in one of two
1144448027ebSBryan Cantrill * states that we cannot differentiate between: the cursor is
1145448027ebSBryan Cantrill * either on the right margin of the previous line (having not
1146448027ebSBryan Cantrill * advanced due to the lazy wrap) _or_ the cursor is on the
1147448027ebSBryan Cantrill * left margin of the current line because a wrap has already
1148448027ebSBryan Cantrill * been induced due to prior activity. Because these cases are
1149448027ebSBryan Cantrill * impossible to differentiate, we force the latter case by
1150448027ebSBryan Cantrill * emitting a space and then moving the cursor back. If the
1151448027ebSBryan Cantrill * wrap had not been induced, emitting this space will induce
1152448027ebSBryan Cantrill * it -- and will assure that our termio_backleft() is the
1153448027ebSBryan Cantrill * correct behavior with respect to the cursor.
1154448027ebSBryan Cantrill */
1155448027ebSBryan Cantrill if (td->tio_flags & TIO_LAZYWRAP) {
1156448027ebSBryan Cantrill mdb_iob_putc(td->tio_out, ' ');
1157448027ebSBryan Cantrill termio_tput(td, td->tio_info.ti_cub1.at_str, 1);
1158448027ebSBryan Cantrill }
1159448027ebSBryan Cantrill
11607c478bd9Sstevel@tonic-gate termio_backleft(td);
11617c478bd9Sstevel@tonic-gate td->tio_x = td->tio_cols - 1;
11627c478bd9Sstevel@tonic-gate td->tio_y--;
11637c478bd9Sstevel@tonic-gate } else {
11647c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_cub1.at_str, 1);
11657c478bd9Sstevel@tonic-gate td->tio_x--;
11667c478bd9Sstevel@tonic-gate }
11677c478bd9Sstevel@tonic-gate
11687c478bd9Sstevel@tonic-gate termio_delch(td);
11697c478bd9Sstevel@tonic-gate }
11707c478bd9Sstevel@tonic-gate
11717c478bd9Sstevel@tonic-gate static void
termio_delch(termio_data_t * td)11727c478bd9Sstevel@tonic-gate termio_delch(termio_data_t *td)
11737c478bd9Sstevel@tonic-gate {
11747c478bd9Sstevel@tonic-gate mdb_iob_putc(td->tio_out, ' ');
11757c478bd9Sstevel@tonic-gate
1176448027ebSBryan Cantrill if (td->tio_x == td->tio_cols - 1 && (td->tio_flags & TIO_AUTOWRAP)) {
1177448027ebSBryan Cantrill /*
1178448027ebSBryan Cantrill * We just overwrote a space in the final column, so we know
1179448027ebSBryan Cantrill * that we have autowrapped and we therefore definitely don't
1180448027ebSBryan Cantrill * want to issue the ti_cub1. If we have TIO_LAZYWRAP, we know
1181448027ebSBryan Cantrill * that the cursor remains on the final column, and we want to
1182448027ebSBryan Cantrill * do nothing -- but if TIO_LAZYWRAP isn't set, we have wrapped
1183448027ebSBryan Cantrill * and we need to move the cursor back up and all the way to
1184448027ebSBryan Cantrill * the right via termio_backleft().
1185448027ebSBryan Cantrill */
1186448027ebSBryan Cantrill if (!(td->tio_flags & TIO_LAZYWRAP))
1187448027ebSBryan Cantrill termio_backleft(td);
1188448027ebSBryan Cantrill } else {
11897c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_cub1.at_str, 1);
1190448027ebSBryan Cantrill }
11917c478bd9Sstevel@tonic-gate
11927c478bd9Sstevel@tonic-gate mdb_iob_flush(td->tio_out);
11937c478bd9Sstevel@tonic-gate }
11947c478bd9Sstevel@tonic-gate
11957c478bd9Sstevel@tonic-gate static void
termio_clear(termio_data_t * td)11967c478bd9Sstevel@tonic-gate termio_clear(termio_data_t *td)
11977c478bd9Sstevel@tonic-gate {
11987c478bd9Sstevel@tonic-gate while (td->tio_x-- != 0)
11997c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_cub1.at_str, 1);
12007c478bd9Sstevel@tonic-gate
12017c478bd9Sstevel@tonic-gate while (td->tio_y < td->tio_max_y) {
12027c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_cud1.at_str, 1);
12037c478bd9Sstevel@tonic-gate td->tio_y++;
12047c478bd9Sstevel@tonic-gate }
12057c478bd9Sstevel@tonic-gate
12067c478bd9Sstevel@tonic-gate while (td->tio_y-- != 0) {
12077c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_el.at_str, 1);
12087c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_cuu1.at_str, 1);
12097c478bd9Sstevel@tonic-gate }
12107c478bd9Sstevel@tonic-gate
12117c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_el.at_str, 1);
12127c478bd9Sstevel@tonic-gate mdb_iob_flush(td->tio_out);
12137c478bd9Sstevel@tonic-gate
12147c478bd9Sstevel@tonic-gate termio_prompt(td);
12157c478bd9Sstevel@tonic-gate }
12167c478bd9Sstevel@tonic-gate
12177c478bd9Sstevel@tonic-gate static void
termio_redraw(termio_data_t * td)12187c478bd9Sstevel@tonic-gate termio_redraw(termio_data_t *td)
12197c478bd9Sstevel@tonic-gate {
12207c478bd9Sstevel@tonic-gate const char *buf = td->tio_cmdbuf.cmd_buf;
12217c478bd9Sstevel@tonic-gate size_t len = td->tio_cmdbuf.cmd_buflen;
12227c478bd9Sstevel@tonic-gate size_t pos, n;
12237c478bd9Sstevel@tonic-gate
12247c478bd9Sstevel@tonic-gate termio_clear(td);
12257c478bd9Sstevel@tonic-gate
12267c478bd9Sstevel@tonic-gate if (len == 0)
12277c478bd9Sstevel@tonic-gate return; /* if the buffer is empty, we're done */
12287c478bd9Sstevel@tonic-gate
12297c478bd9Sstevel@tonic-gate if (td->tio_flags & TIO_AUTOWRAP)
12307c478bd9Sstevel@tonic-gate mdb_iob_nputs(td->tio_out, buf, len);
12317c478bd9Sstevel@tonic-gate else {
12327c478bd9Sstevel@tonic-gate for (pos = td->tio_promptlen; len != 0; pos = 0) {
12337c478bd9Sstevel@tonic-gate n = MIN(td->tio_cols - pos, len);
12347c478bd9Sstevel@tonic-gate mdb_iob_nputs(td->tio_out, buf, n);
12357c478bd9Sstevel@tonic-gate buf += n;
12367c478bd9Sstevel@tonic-gate len -= n;
12377c478bd9Sstevel@tonic-gate
12387c478bd9Sstevel@tonic-gate if (pos + n == td->tio_cols)
12397c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_nel.at_str, 1);
12407c478bd9Sstevel@tonic-gate }
12417c478bd9Sstevel@tonic-gate }
12427c478bd9Sstevel@tonic-gate
12437c478bd9Sstevel@tonic-gate pos = td->tio_promptlen + td->tio_cmdbuf.cmd_buflen;
12447c478bd9Sstevel@tonic-gate td->tio_x = pos % td->tio_cols;
12457c478bd9Sstevel@tonic-gate td->tio_y = pos / td->tio_cols;
12467c478bd9Sstevel@tonic-gate
12477c478bd9Sstevel@tonic-gate mdb_iob_flush(td->tio_out);
12487c478bd9Sstevel@tonic-gate termio_mvcur(td);
12497c478bd9Sstevel@tonic-gate }
12507c478bd9Sstevel@tonic-gate
12517c478bd9Sstevel@tonic-gate static void
termio_prompt(termio_data_t * td)12527c478bd9Sstevel@tonic-gate termio_prompt(termio_data_t *td)
12537c478bd9Sstevel@tonic-gate {
12547c478bd9Sstevel@tonic-gate mdb_callb_fire(MDB_CALLB_PROMPT);
12557c478bd9Sstevel@tonic-gate
12567c478bd9Sstevel@tonic-gate /*
12577c478bd9Sstevel@tonic-gate * Findhist (^R) overrides the displayed prompt. We should only update
12587c478bd9Sstevel@tonic-gate * the main prompt (which may have been changed by the callback) if
12597c478bd9Sstevel@tonic-gate * findhist isn't active.
12607c478bd9Sstevel@tonic-gate */
12617c478bd9Sstevel@tonic-gate if (!(td->tio_flags & TIO_FINDHIST)) {
12627c478bd9Sstevel@tonic-gate td->tio_prompt = mdb.m_prompt;
12637c478bd9Sstevel@tonic-gate td->tio_promptlen = mdb.m_promptlen;
12647c478bd9Sstevel@tonic-gate }
12657c478bd9Sstevel@tonic-gate
12667c478bd9Sstevel@tonic-gate mdb_iob_puts(td->tio_out, td->tio_prompt);
12677c478bd9Sstevel@tonic-gate mdb_iob_flush(td->tio_out);
12687c478bd9Sstevel@tonic-gate
12697c478bd9Sstevel@tonic-gate td->tio_x = td->tio_promptlen;
12707c478bd9Sstevel@tonic-gate td->tio_y = 0;
12717c478bd9Sstevel@tonic-gate }
12727c478bd9Sstevel@tonic-gate
12737c478bd9Sstevel@tonic-gate /*
12747c478bd9Sstevel@tonic-gate * For debugging purposes, iterate over the table of attributes and output them
12757c478bd9Sstevel@tonic-gate * in human readable form for verification.
12767c478bd9Sstevel@tonic-gate */
12777c478bd9Sstevel@tonic-gate static void
termio_dump(termio_data_t * td,const termio_attr_t * ta)12787c478bd9Sstevel@tonic-gate termio_dump(termio_data_t *td, const termio_attr_t *ta)
12797c478bd9Sstevel@tonic-gate {
12807c478bd9Sstevel@tonic-gate char *str;
12817c478bd9Sstevel@tonic-gate
12827c478bd9Sstevel@tonic-gate for (; ta->ta_name != NULL; ta++) {
12837c478bd9Sstevel@tonic-gate switch (ta->ta_type) {
12847c478bd9Sstevel@tonic-gate case TIO_ATTR_REQSTR:
12857c478bd9Sstevel@tonic-gate case TIO_ATTR_STR:
12867c478bd9Sstevel@tonic-gate if (ta->ta_valp->at_str != NULL) {
12877c478bd9Sstevel@tonic-gate str = strchr2esc(ta->ta_valp->at_str,
12887c478bd9Sstevel@tonic-gate strlen(ta->ta_valp->at_str));
12897c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_CMDBUF, "%s = \"%s\"\n",
12907c478bd9Sstevel@tonic-gate ta->ta_name, str);
12917c478bd9Sstevel@tonic-gate strfree(str);
12927c478bd9Sstevel@tonic-gate } else {
12937c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_CMDBUF, "%s = <NULL>\n",
12947c478bd9Sstevel@tonic-gate ta->ta_name);
12957c478bd9Sstevel@tonic-gate }
12967c478bd9Sstevel@tonic-gate break;
12977c478bd9Sstevel@tonic-gate case TIO_ATTR_INT:
12987c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_CMDBUF, "%s = %d\n",
12997c478bd9Sstevel@tonic-gate ta->ta_name, ta->ta_valp->at_val);
13007c478bd9Sstevel@tonic-gate break;
13017c478bd9Sstevel@tonic-gate case TIO_ATTR_BOOL:
13027c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_CMDBUF, "%s = %s\n", ta->ta_name,
13037c478bd9Sstevel@tonic-gate ta->ta_valp->at_val ? "TRUE" : "FALSE");
13047c478bd9Sstevel@tonic-gate break;
13057c478bd9Sstevel@tonic-gate }
13067c478bd9Sstevel@tonic-gate }
13077c478bd9Sstevel@tonic-gate
13087c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_CMDBUF, "tio_flags = <%#b>\n",
13097c478bd9Sstevel@tonic-gate td->tio_flags, tio_flag_masks);
13107c478bd9Sstevel@tonic-gate }
13117c478bd9Sstevel@tonic-gate
13127c478bd9Sstevel@tonic-gate static int
termio_setup_attrs(termio_data_t * td,const char * name)13137c478bd9Sstevel@tonic-gate termio_setup_attrs(termio_data_t *td, const char *name)
13147c478bd9Sstevel@tonic-gate {
13157c478bd9Sstevel@tonic-gate const termio_attr_t *ta;
13167c478bd9Sstevel@tonic-gate const char *str;
13177c478bd9Sstevel@tonic-gate size_t nbytes;
13187c478bd9Sstevel@tonic-gate char *bufp;
13197c478bd9Sstevel@tonic-gate
13207c478bd9Sstevel@tonic-gate int need_padding = 0;
13217c478bd9Sstevel@tonic-gate int i;
13227c478bd9Sstevel@tonic-gate
13237c478bd9Sstevel@tonic-gate /*
13247c478bd9Sstevel@tonic-gate * Load terminal attributes:
13257c478bd9Sstevel@tonic-gate */
13267c478bd9Sstevel@tonic-gate for (nbytes = 0, ta = &termio_attrs[0]; ta->ta_name != NULL; ta++) {
13277c478bd9Sstevel@tonic-gate switch (ta->ta_type) {
13287c478bd9Sstevel@tonic-gate case TIO_ATTR_REQSTR:
13297c478bd9Sstevel@tonic-gate case TIO_ATTR_STR:
13307c478bd9Sstevel@tonic-gate str = tigetstr(ta->ta_name);
13317c478bd9Sstevel@tonic-gate
13327c478bd9Sstevel@tonic-gate if (str == (const char *)-1) {
13337c478bd9Sstevel@tonic-gate termio_warn(td, TIO_CAPWARN,
13347c478bd9Sstevel@tonic-gate "terminal capability '%s' is not of type "
13357c478bd9Sstevel@tonic-gate "string as expected\n", ta->ta_name);
13367c478bd9Sstevel@tonic-gate return (0);
13377c478bd9Sstevel@tonic-gate }
13387c478bd9Sstevel@tonic-gate
13397c478bd9Sstevel@tonic-gate if (str != NULL)
13407c478bd9Sstevel@tonic-gate nbytes += strlen(str) + 1;
13417c478bd9Sstevel@tonic-gate else if (ta->ta_type == TIO_ATTR_REQSTR) {
13427c478bd9Sstevel@tonic-gate termio_warn(td, TIO_CAPWARN,
13437c478bd9Sstevel@tonic-gate "terminal capability '%s' is not "
13447c478bd9Sstevel@tonic-gate "available\n", ta->ta_name);
13457c478bd9Sstevel@tonic-gate return (0);
13467c478bd9Sstevel@tonic-gate }
13477c478bd9Sstevel@tonic-gate break;
13487c478bd9Sstevel@tonic-gate
13497c478bd9Sstevel@tonic-gate case TIO_ATTR_BOOL:
13507c478bd9Sstevel@tonic-gate if (tigetflag(ta->ta_name) == -1) {
13517c478bd9Sstevel@tonic-gate termio_warn(td, TIO_CAPWARN,
13527c478bd9Sstevel@tonic-gate "terminal capability '%s' is not of type "
13537c478bd9Sstevel@tonic-gate "boolean as expected\n", ta->ta_name);
13547c478bd9Sstevel@tonic-gate return (0);
13557c478bd9Sstevel@tonic-gate }
13567c478bd9Sstevel@tonic-gate break;
13577c478bd9Sstevel@tonic-gate
13587c478bd9Sstevel@tonic-gate case TIO_ATTR_INT:
13597c478bd9Sstevel@tonic-gate if (tigetnum(ta->ta_name) == -2) {
13607c478bd9Sstevel@tonic-gate termio_warn(td, TIO_CAPWARN,
13617c478bd9Sstevel@tonic-gate "terminal capability '%s' is not of type "
13627c478bd9Sstevel@tonic-gate "integer as expected\n", ta->ta_name);
13637c478bd9Sstevel@tonic-gate return (0);
13647c478bd9Sstevel@tonic-gate }
13657c478bd9Sstevel@tonic-gate break;
13667c478bd9Sstevel@tonic-gate }
13677c478bd9Sstevel@tonic-gate }
13687c478bd9Sstevel@tonic-gate
13697c478bd9Sstevel@tonic-gate if (nbytes != 0)
13707c478bd9Sstevel@tonic-gate td->tio_attrs = mdb_alloc(nbytes, UM_SLEEP);
13717c478bd9Sstevel@tonic-gate else
13727c478bd9Sstevel@tonic-gate td->tio_attrs = NULL;
13737c478bd9Sstevel@tonic-gate
13747c478bd9Sstevel@tonic-gate td->tio_attrslen = nbytes;
13757c478bd9Sstevel@tonic-gate bufp = td->tio_attrs;
13767c478bd9Sstevel@tonic-gate
13777c478bd9Sstevel@tonic-gate /*
13787c478bd9Sstevel@tonic-gate * Now make another pass through the terminal attributes and load the
13797c478bd9Sstevel@tonic-gate * actual pointers into our static data structure:
13807c478bd9Sstevel@tonic-gate */
13817c478bd9Sstevel@tonic-gate for (ta = &termio_attrs[0]; ta->ta_name != NULL; ta++) {
13827c478bd9Sstevel@tonic-gate switch (ta->ta_type) {
13837c478bd9Sstevel@tonic-gate case TIO_ATTR_REQSTR:
13847c478bd9Sstevel@tonic-gate case TIO_ATTR_STR:
13857c478bd9Sstevel@tonic-gate if ((str = tigetstr(ta->ta_name)) != NULL) {
13867c478bd9Sstevel@tonic-gate /*
13877c478bd9Sstevel@tonic-gate * Copy the result string into our contiguous
13887c478bd9Sstevel@tonic-gate * buffer, and store a pointer to it in at_str.
13897c478bd9Sstevel@tonic-gate */
13907c478bd9Sstevel@tonic-gate (void) strcpy(bufp, str);
13917c478bd9Sstevel@tonic-gate ta->ta_valp->at_str = bufp;
13927c478bd9Sstevel@tonic-gate bufp += strlen(str) + 1;
13937c478bd9Sstevel@tonic-gate /*
13947c478bd9Sstevel@tonic-gate * Check the string for a "$<>" pad sequence;
13957c478bd9Sstevel@tonic-gate * if none are found, we can optimize later.
13967c478bd9Sstevel@tonic-gate */
13977c478bd9Sstevel@tonic-gate if ((str = strstr(ta->ta_valp->at_str,
13987c478bd9Sstevel@tonic-gate "$<")) != NULL && strchr(str, '>') != NULL)
13997c478bd9Sstevel@tonic-gate need_padding++;
14007c478bd9Sstevel@tonic-gate } else {
14017c478bd9Sstevel@tonic-gate ta->ta_valp->at_str = NULL;
14027c478bd9Sstevel@tonic-gate }
14037c478bd9Sstevel@tonic-gate break;
14047c478bd9Sstevel@tonic-gate
14057c478bd9Sstevel@tonic-gate case TIO_ATTR_BOOL:
14067c478bd9Sstevel@tonic-gate ta->ta_valp->at_val = tigetflag(ta->ta_name);
14077c478bd9Sstevel@tonic-gate break;
14087c478bd9Sstevel@tonic-gate
14097c478bd9Sstevel@tonic-gate case TIO_ATTR_INT:
14107c478bd9Sstevel@tonic-gate ta->ta_valp->at_val = tigetnum(ta->ta_name);
14117c478bd9Sstevel@tonic-gate break;
14127c478bd9Sstevel@tonic-gate }
14137c478bd9Sstevel@tonic-gate }
14147c478bd9Sstevel@tonic-gate
14157c478bd9Sstevel@tonic-gate /*
14167c478bd9Sstevel@tonic-gate * Copy attribute pointers from temporary struct into td->tio_info:
14177c478bd9Sstevel@tonic-gate */
14187c478bd9Sstevel@tonic-gate bcopy(&termio_info, &td->tio_info, sizeof (termio_info_t));
14197c478bd9Sstevel@tonic-gate
14207c478bd9Sstevel@tonic-gate /*
14217c478bd9Sstevel@tonic-gate * Initialize the terminal size based on the terminfo database. If it
14227c478bd9Sstevel@tonic-gate * does not have the relevant properties, fall back to the environment
14237c478bd9Sstevel@tonic-gate * settings or to a hardcoded default. These settings will only be
14247c478bd9Sstevel@tonic-gate * used if we subsequently fail to derive the size with TIOCGWINSZ.
14257c478bd9Sstevel@tonic-gate */
14267c478bd9Sstevel@tonic-gate td->tio_rows = MAX(td->tio_info.ti_lines.at_val, 0);
14277c478bd9Sstevel@tonic-gate td->tio_cols = MAX(td->tio_info.ti_cols.at_val, 0);
14287c478bd9Sstevel@tonic-gate
14297c478bd9Sstevel@tonic-gate if (td->tio_rows == 0) {
14307c478bd9Sstevel@tonic-gate if ((str = getenv("LINES")) != NULL && strisnum(str) != 0 &&
14317c478bd9Sstevel@tonic-gate (i = strtoi(str)) > 0)
14327c478bd9Sstevel@tonic-gate td->tio_rows = i;
14337c478bd9Sstevel@tonic-gate else
14347c478bd9Sstevel@tonic-gate td->tio_rows = TIO_DEFAULT_ROWS;
14357c478bd9Sstevel@tonic-gate }
14367c478bd9Sstevel@tonic-gate
14377c478bd9Sstevel@tonic-gate if (td->tio_cols == 0) {
14387c478bd9Sstevel@tonic-gate if ((str = getenv("COLUMNS")) != NULL && strisnum(str) != 0 &&
14397c478bd9Sstevel@tonic-gate (i = strtoi(str)) > 0)
14407c478bd9Sstevel@tonic-gate td->tio_cols = i;
14417c478bd9Sstevel@tonic-gate else
14427c478bd9Sstevel@tonic-gate td->tio_cols = TIO_DEFAULT_COLS;
14437c478bd9Sstevel@tonic-gate }
14447c478bd9Sstevel@tonic-gate
14457c478bd9Sstevel@tonic-gate td->tio_flags = 0;
14467c478bd9Sstevel@tonic-gate
1447448027ebSBryan Cantrill /*
1448448027ebSBryan Cantrill * We turn on TIO_AUTOWRAP if "am" (automargin) is set on the terminal.
1449448027ebSBryan Cantrill * Previously, this check was too smart for its own good, turning
1450448027ebSBryan Cantrill * TIO_AUTOWRAP on only when both "am" was set _and_ "xenl" was unset.
1451448027ebSBryan Cantrill * "xenl" is one of the (infamous?) so-called "Xanthippe glitches",
1452448027ebSBryan Cantrill * this one pertaining to the Concept 100's feature of not autowrapping
1453448027ebSBryan Cantrill * if the autowrap-inducing character is a newline. (That is, the
1454448027ebSBryan Cantrill * newline was "eaten" in this case -- and "xenl" accordingly stands
1455448027ebSBryan Cantrill * for "Xanthippe eat newline", which itself sounds like a command from
1456448027ebSBryan Cantrill * an Infocom game about line discipline set in ancient Greece.) This
1457448027ebSBryan Cantrill * (now removed) condition misunderstood the semantics of "xenl",
1458448027ebSBryan Cantrill * apparently inferring that its presence denoted that the terminal
1459448027ebSBryan Cantrill * could not autowrap at all. In fact, "xenl" is commonly set, and
1460448027ebSBryan Cantrill * denotes that the terminal will not autowrap on a newline -- a
1461448027ebSBryan Cantrill * feature (nee glitch) that is not particularly relevant with respect
1462448027ebSBryan Cantrill * to our input processing. (Ironically, disabling TIO_AUTOWRAP in
1463448027ebSBryan Cantrill * this case only results in correct-seeming output because of the
1464448027ebSBryan Cantrill * presence of the feature, as the inserted newline to force the wrap
1465448027ebSBryan Cantrill * isn't actually displayed; were it displayed, the input buffer would
1466448027ebSBryan Cantrill * appear double-spaced.) So with respect to "xenl" and autowrapping,
1467448027ebSBryan Cantrill * the correct behavior is to ignore it entirely, and adopt the
1468448027ebSBryan Cantrill * (simpler and less arcane) logic of setting TIO_AUTOWRAP if (and only
1469448027ebSBryan Cantrill * if) "am" is set on the terminal. This does not, however, mean that
1470448027ebSBryan Cantrill * "xenl" is meaningless; see below...
1471448027ebSBryan Cantrill */
1472448027ebSBryan Cantrill if (td->tio_info.ti_am.at_val)
14737c478bd9Sstevel@tonic-gate td->tio_flags |= TIO_AUTOWRAP;
14747c478bd9Sstevel@tonic-gate
1475448027ebSBryan Cantrill /*
1476448027ebSBryan Cantrill * While "xenl" doesn't dictate our TIO_AUTOWRAP setting, it does have
1477448027ebSBryan Cantrill * a subtle impact on the way we process input: in addition to its
1478448027ebSBryan Cantrill * eponymous behavior of eating newlines, "xenl" denotes a second,
1479bbf21555SRichard Lowe * entirely orthogonal idiosyncracy. As terminfo(5) tells it: "Those
1480448027ebSBryan Cantrill * terminals whose cursor remains on the right-most column until
1481448027ebSBryan Cantrill * another character has been received, rather than wrapping
1482448027ebSBryan Cantrill * immediately upon receiving the right- most character, such as the
1483448027ebSBryan Cantrill * VT100, should also indicate xenl." So yes, "xenl" in fact has two
1484448027ebSBryan Cantrill * entirely different meanings -- it is a glitch-within-a-glitch, in
1485448027ebSBryan Cantrill * what one assumes (hopes?) to be an accident of history rather than a
1486448027ebSBryan Cantrill * deliberate act of sabotage. This second behavior is relevant to us
1487448027ebSBryan Cantrill * because it affects the way we redraw the screen after a backspace in
1488448027ebSBryan Cantrill * the left-most column. We call this second behavior "lazy wrapping",
1489448027ebSBryan Cantrill * and we set it if (and only if) "xenl" is set on the terminal.
1490448027ebSBryan Cantrill */
1491448027ebSBryan Cantrill if (td->tio_info.ti_xenl.at_val)
1492448027ebSBryan Cantrill td->tio_flags |= TIO_LAZYWRAP;
1493448027ebSBryan Cantrill
14947c478bd9Sstevel@tonic-gate if (td->tio_info.ti_bw.at_val)
14957c478bd9Sstevel@tonic-gate td->tio_flags |= TIO_BACKLEFT;
14967c478bd9Sstevel@tonic-gate
14977c478bd9Sstevel@tonic-gate if (td->tio_info.ti_smir.at_str != NULL ||
14987c478bd9Sstevel@tonic-gate td->tio_info.ti_ich1.at_str != NULL)
14997c478bd9Sstevel@tonic-gate td->tio_flags |= TIO_INSERT;
15007c478bd9Sstevel@tonic-gate
15017c478bd9Sstevel@tonic-gate if (mdb.m_flags & MDB_FL_USECUP)
15027c478bd9Sstevel@tonic-gate td->tio_flags |= TIO_USECUP;
15037c478bd9Sstevel@tonic-gate
15047c478bd9Sstevel@tonic-gate if (name != NULL && (strncmp(name, "xterm", 5) == 0 ||
15057c478bd9Sstevel@tonic-gate strcmp(name, "dtterm") == 0))
15067c478bd9Sstevel@tonic-gate td->tio_flags |= TIO_XTERM;
15077c478bd9Sstevel@tonic-gate
15087c478bd9Sstevel@tonic-gate /*
15097c478bd9Sstevel@tonic-gate * Optimizations for padding: (1) if no pad attribute is present, set
15107c478bd9Sstevel@tonic-gate * its value to "\0" to avoid testing later; (2) if no pad sequences
15117c478bd9Sstevel@tonic-gate * were found, force "npc" to TRUE so we pick the optimized tio_putp;
15127c478bd9Sstevel@tonic-gate * (3) if the padding baud property is not present, reset it to zero
15137c478bd9Sstevel@tonic-gate * since we need to compare it to an unsigned baud value.
15147c478bd9Sstevel@tonic-gate */
15157c478bd9Sstevel@tonic-gate if (td->tio_info.ti_pad.at_str == NULL)
15167c478bd9Sstevel@tonic-gate td->tio_info.ti_pad.at_str = ""; /* \0 is the pad char */
15177c478bd9Sstevel@tonic-gate
15187c478bd9Sstevel@tonic-gate if (need_padding == 0)
15197c478bd9Sstevel@tonic-gate td->tio_info.ti_npc.at_val = TRUE;
15207c478bd9Sstevel@tonic-gate
15217c478bd9Sstevel@tonic-gate if (td->tio_info.ti_npc.at_val)
15227c478bd9Sstevel@tonic-gate td->tio_putp = &termio_puts;
15237c478bd9Sstevel@tonic-gate else
15247c478bd9Sstevel@tonic-gate td->tio_putp = &termio_putp;
15257c478bd9Sstevel@tonic-gate
15267c478bd9Sstevel@tonic-gate if (td->tio_info.ti_pb.at_val < 0)
15277c478bd9Sstevel@tonic-gate td->tio_info.ti_pb.at_val = 0;
15287c478bd9Sstevel@tonic-gate
15297c478bd9Sstevel@tonic-gate /*
15307c478bd9Sstevel@tonic-gate * If no newline capability is available, assume \r\n will work. If no
15317c478bd9Sstevel@tonic-gate * carriage return capability is available, assume \r will work.
15327c478bd9Sstevel@tonic-gate */
15337c478bd9Sstevel@tonic-gate if (td->tio_info.ti_nel.at_str == NULL)
15347c478bd9Sstevel@tonic-gate td->tio_info.ti_nel.at_str = "\r\n";
15357c478bd9Sstevel@tonic-gate if (td->tio_info.ti_cr.at_str == NULL)
15367c478bd9Sstevel@tonic-gate td->tio_info.ti_cr.at_str = "\r";
15377c478bd9Sstevel@tonic-gate
15387c478bd9Sstevel@tonic-gate return (1);
15397c478bd9Sstevel@tonic-gate }
15407c478bd9Sstevel@tonic-gate
15417c478bd9Sstevel@tonic-gate mdb_io_t *
mdb_termio_create(const char * name,mdb_io_t * rio,mdb_io_t * wio)15427c478bd9Sstevel@tonic-gate mdb_termio_create(const char *name, mdb_io_t *rio, mdb_io_t *wio)
15437c478bd9Sstevel@tonic-gate {
15447c478bd9Sstevel@tonic-gate struct termios otios;
15457c478bd9Sstevel@tonic-gate termio_data_t *td;
15467c478bd9Sstevel@tonic-gate int rv, err, i;
15477c478bd9Sstevel@tonic-gate
15487c478bd9Sstevel@tonic-gate td = mdb_zalloc(sizeof (termio_data_t), UM_SLEEP);
15497c478bd9Sstevel@tonic-gate td->tio_io = mdb_alloc(sizeof (mdb_io_t), UM_SLEEP);
15507c478bd9Sstevel@tonic-gate
15517c478bd9Sstevel@tonic-gate /*
15527c478bd9Sstevel@tonic-gate * Save the original user settings before calling setupterm(), which
15537c478bd9Sstevel@tonic-gate * cleverly changes them without telling us what it did or why.
15547c478bd9Sstevel@tonic-gate */
15557c478bd9Sstevel@tonic-gate if (IOP_CTL(rio, TCGETS, &otios) == -1) {
15567c478bd9Sstevel@tonic-gate warn("failed to read terminal attributes for stdin");
15577c478bd9Sstevel@tonic-gate goto err;
15587c478bd9Sstevel@tonic-gate }
15597c478bd9Sstevel@tonic-gate
15607c478bd9Sstevel@tonic-gate rv = setupterm((char *)name, IOP_CTL(rio, MDB_IOC_GETFD, NULL), &err);
15617c478bd9Sstevel@tonic-gate IOP_CTL(rio, TCSETSW, &otios); /* undo setupterm() stupidity */
15627c478bd9Sstevel@tonic-gate
15637c478bd9Sstevel@tonic-gate if (rv == ERR) {
15647c478bd9Sstevel@tonic-gate if (err == 0)
15657c478bd9Sstevel@tonic-gate warn("no terminal data available for TERM=%s\n", name);
15667c478bd9Sstevel@tonic-gate else if (err == -1)
15677c478bd9Sstevel@tonic-gate warn("failed to locate terminfo database\n");
15687c478bd9Sstevel@tonic-gate else
15697c478bd9Sstevel@tonic-gate warn("failed to initialize terminal (err=%d)\n", err);
15707c478bd9Sstevel@tonic-gate goto err;
15717c478bd9Sstevel@tonic-gate }
15727c478bd9Sstevel@tonic-gate
15737c478bd9Sstevel@tonic-gate if (!termio_setup_attrs(td, name))
15747c478bd9Sstevel@tonic-gate goto err;
15757c478bd9Sstevel@tonic-gate
15767c478bd9Sstevel@tonic-gate /*
15777c478bd9Sstevel@tonic-gate * Do not re-issue terminal capability warnings when mdb re-execs.
15787c478bd9Sstevel@tonic-gate */
15797c478bd9Sstevel@tonic-gate if (mdb.m_flags & MDB_FL_EXEC)
15807c478bd9Sstevel@tonic-gate td->tio_flags |= TIO_TTYWARN | TIO_CAPWARN;
15817c478bd9Sstevel@tonic-gate
15827c478bd9Sstevel@tonic-gate /*
15837c478bd9Sstevel@tonic-gate * Initialize i/o structures and command-line buffer:
15847c478bd9Sstevel@tonic-gate */
15857c478bd9Sstevel@tonic-gate td->tio_io->io_ops = &termio_ops;
15867c478bd9Sstevel@tonic-gate td->tio_io->io_data = td;
15877c478bd9Sstevel@tonic-gate td->tio_io->io_next = NULL;
15887c478bd9Sstevel@tonic-gate td->tio_io->io_refcnt = 0;
15897c478bd9Sstevel@tonic-gate
15907c478bd9Sstevel@tonic-gate td->tio_in_io = rio;
15917c478bd9Sstevel@tonic-gate td->tio_in = mdb_iob_create(td->tio_in_io, MDB_IOB_RDONLY);
15927c478bd9Sstevel@tonic-gate
15937c478bd9Sstevel@tonic-gate td->tio_out_io = wio;
15947c478bd9Sstevel@tonic-gate td->tio_out = mdb_iob_create(td->tio_out_io, MDB_IOB_WRONLY);
15957c478bd9Sstevel@tonic-gate mdb_iob_clrflags(td->tio_out, MDB_IOB_AUTOWRAP);
15967c478bd9Sstevel@tonic-gate
15977c478bd9Sstevel@tonic-gate td->tio_link = NULL;
15987c478bd9Sstevel@tonic-gate mdb_cmdbuf_create(&td->tio_cmdbuf);
15997c478bd9Sstevel@tonic-gate
16007c478bd9Sstevel@tonic-gate /*
16017c478bd9Sstevel@tonic-gate * Fill in all the keymap entries with the insert function:
16027c478bd9Sstevel@tonic-gate */
16037c478bd9Sstevel@tonic-gate for (i = 0; i < KEY_MAX; i++)
16047c478bd9Sstevel@tonic-gate td->tio_keymap[i] = termio_insert;
16057c478bd9Sstevel@tonic-gate
16067c478bd9Sstevel@tonic-gate /*
16077c478bd9Sstevel@tonic-gate * Now override selected entries with editing functions:
16087c478bd9Sstevel@tonic-gate */
16097c478bd9Sstevel@tonic-gate td->tio_keymap['\n'] = termio_accept;
16107c478bd9Sstevel@tonic-gate td->tio_keymap['\r'] = termio_accept;
16117c478bd9Sstevel@tonic-gate
16127c478bd9Sstevel@tonic-gate td->tio_keymap[CTRL('f')] = termio_fwdchar;
16137c478bd9Sstevel@tonic-gate td->tio_keymap[CTRL('b')] = termio_backchar;
16147c478bd9Sstevel@tonic-gate td->tio_keymap[CTRL('t')] = termio_transpose;
16157c478bd9Sstevel@tonic-gate td->tio_keymap[CTRL('a')] = termio_home;
16167c478bd9Sstevel@tonic-gate td->tio_keymap[CTRL('e')] = termio_end;
16177c478bd9Sstevel@tonic-gate td->tio_keymap[META('f')] = termio_fwdword;
16187c478bd9Sstevel@tonic-gate td->tio_keymap[META('b')] = termio_backword;
16197c478bd9Sstevel@tonic-gate td->tio_keymap[META('d')] = termio_killfwdword;
16207c478bd9Sstevel@tonic-gate td->tio_keymap[META('\b')] = termio_killbackword;
16217c478bd9Sstevel@tonic-gate td->tio_keymap[CTRL('k')] = termio_kill;
16227c478bd9Sstevel@tonic-gate td->tio_keymap[CTRL('p')] = termio_prevhist;
16237c478bd9Sstevel@tonic-gate td->tio_keymap[CTRL('n')] = termio_nexthist;
16247c478bd9Sstevel@tonic-gate td->tio_keymap[CTRL('r')] = termio_findhist;
16257c478bd9Sstevel@tonic-gate td->tio_keymap[CTRL('l')] = termio_refresh;
16267c478bd9Sstevel@tonic-gate td->tio_keymap[CTRL('d')] = termio_delchar;
16277c478bd9Sstevel@tonic-gate td->tio_keymap[CTRL('?')] = termio_widescreen;
16287c478bd9Sstevel@tonic-gate
1629892f67e4SJoshua M. Clulow td->tio_keymap[KPAD('A')] = termio_prevhist;
1630892f67e4SJoshua M. Clulow td->tio_keymap[KPAD('B')] = termio_nexthist;
1631892f67e4SJoshua M. Clulow td->tio_keymap[KPAD('C')] = termio_fwdchar;
1632892f67e4SJoshua M. Clulow td->tio_keymap[KPAD('D')] = termio_backchar;
1633892f67e4SJoshua M. Clulow
1634892f67e4SJoshua M. Clulow /*
1635892f67e4SJoshua M. Clulow * Many modern terminal emulators treat the "Home" and "End" keys on a
1636892f67e4SJoshua M. Clulow * PC keyboard as cursor keys. Some others use a multibyte function
1637892f67e4SJoshua M. Clulow * key control sequence. We handle both styles here:
1638892f67e4SJoshua M. Clulow */
1639892f67e4SJoshua M. Clulow td->tio_keymap[KPAD('H')] = termio_home;
1640892f67e4SJoshua M. Clulow td->tio_keymap[FKEY('1')] = termio_home;
1641892f67e4SJoshua M. Clulow td->tio_keymap[KPAD('F')] = termio_end;
1642892f67e4SJoshua M. Clulow td->tio_keymap[FKEY('4')] = termio_end;
16437c478bd9Sstevel@tonic-gate
16447c478bd9Sstevel@tonic-gate /*
16457c478bd9Sstevel@tonic-gate * We default both ASCII BS and DEL to termio_backspace for safety. We
16467c478bd9Sstevel@tonic-gate * want backspace to work whenever possible, regardless of whether or
16477c478bd9Sstevel@tonic-gate * not we're able to ask the terminal for the specific character that
16487c478bd9Sstevel@tonic-gate * it will use. kmdb, for example, is not able to make this request,
16497c478bd9Sstevel@tonic-gate * and must be prepared to accept both.
16507c478bd9Sstevel@tonic-gate */
16517c478bd9Sstevel@tonic-gate td->tio_keymap[CTRL('h')] = termio_backspace;
16527c478bd9Sstevel@tonic-gate td->tio_keymap[KEY_DEL] = termio_backspace;
16537c478bd9Sstevel@tonic-gate
16547c478bd9Sstevel@tonic-gate /*
16557c478bd9Sstevel@tonic-gate * Overrides for single-key accelerators
16567c478bd9Sstevel@tonic-gate */
16577c478bd9Sstevel@tonic-gate td->tio_keymap['['] = termio_accel;
16587c478bd9Sstevel@tonic-gate td->tio_keymap[']'] = termio_accel;
16597c478bd9Sstevel@tonic-gate
16603b6e0a59SMatt Amdur /*
16613b6e0a59SMatt Amdur * Grab tabs
16623b6e0a59SMatt Amdur */
16633b6e0a59SMatt Amdur td->tio_keymap['\t'] = termio_tab;
16643b6e0a59SMatt Amdur
16657c478bd9Sstevel@tonic-gate td->tio_x = 0;
16667c478bd9Sstevel@tonic-gate td->tio_y = 0;
16677c478bd9Sstevel@tonic-gate td->tio_max_x = 0;
16687c478bd9Sstevel@tonic-gate td->tio_max_y = 0;
16697c478bd9Sstevel@tonic-gate
16707c478bd9Sstevel@tonic-gate td->tio_active = FALSE;
16717c478bd9Sstevel@tonic-gate td->tio_rti_on = FALSE;
16727c478bd9Sstevel@tonic-gate td->tio_suspended = 1;
16737c478bd9Sstevel@tonic-gate
16747c478bd9Sstevel@tonic-gate /*
16757c478bd9Sstevel@tonic-gate * Perform a resume operation to complete our terminal initialization,
16767c478bd9Sstevel@tonic-gate * and then adjust the keymap according to the terminal settings.
16777c478bd9Sstevel@tonic-gate */
16787c478bd9Sstevel@tonic-gate termio_resume_tty(td, &td->tio_ptios);
16797c478bd9Sstevel@tonic-gate bcopy(&td->tio_ptios, &td->tio_ctios, sizeof (struct termios));
16807c478bd9Sstevel@tonic-gate
16817c478bd9Sstevel@tonic-gate td->tio_keymap[td->tio_intr] = termio_intr;
16827c478bd9Sstevel@tonic-gate td->tio_keymap[td->tio_quit] = termio_quit;
16837c478bd9Sstevel@tonic-gate td->tio_keymap[td->tio_erase] = termio_backspace;
16847c478bd9Sstevel@tonic-gate td->tio_keymap[td->tio_werase] = termio_killbackword;
16857c478bd9Sstevel@tonic-gate td->tio_keymap[td->tio_kill] = termio_reset;
16867c478bd9Sstevel@tonic-gate td->tio_keymap[td->tio_susp] = termio_susp;
16877c478bd9Sstevel@tonic-gate
16887c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGWINCH, termio_winch, td);
16897c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGTSTP, termio_tstp, td);
16907c478bd9Sstevel@tonic-gate
16917c478bd9Sstevel@tonic-gate if (mdb.m_debug & MDB_DBG_CMDBUF)
16927c478bd9Sstevel@tonic-gate termio_dump(td, &termio_attrs[0]);
16937c478bd9Sstevel@tonic-gate
16947c478bd9Sstevel@tonic-gate return (td->tio_io);
16957c478bd9Sstevel@tonic-gate
16967c478bd9Sstevel@tonic-gate err:
16977c478bd9Sstevel@tonic-gate mdb_free(td->tio_io, sizeof (mdb_io_t));
16987c478bd9Sstevel@tonic-gate mdb_free(td, sizeof (termio_data_t));
16997c478bd9Sstevel@tonic-gate
17007c478bd9Sstevel@tonic-gate return (NULL);
17017c478bd9Sstevel@tonic-gate }
17027c478bd9Sstevel@tonic-gate
17037c478bd9Sstevel@tonic-gate int
mdb_iob_isatty(mdb_iob_t * iob)17047c478bd9Sstevel@tonic-gate mdb_iob_isatty(mdb_iob_t *iob)
17057c478bd9Sstevel@tonic-gate {
17067c478bd9Sstevel@tonic-gate mdb_io_t *io;
17077c478bd9Sstevel@tonic-gate
17087c478bd9Sstevel@tonic-gate if (iob->iob_flags & MDB_IOB_TTYLIKE)
17097c478bd9Sstevel@tonic-gate return (1);
17107c478bd9Sstevel@tonic-gate
17117c478bd9Sstevel@tonic-gate for (io = iob->iob_iop; io != NULL; io = io->io_next) {
17127c478bd9Sstevel@tonic-gate if (io->io_ops == &termio_ops)
17137c478bd9Sstevel@tonic-gate return (1);
17147c478bd9Sstevel@tonic-gate }
17157c478bd9Sstevel@tonic-gate
17167c478bd9Sstevel@tonic-gate return (0);
17177c478bd9Sstevel@tonic-gate }
17187c478bd9Sstevel@tonic-gate
17197c478bd9Sstevel@tonic-gate static const char *
termio_insert(termio_data_t * td,int c)17207c478bd9Sstevel@tonic-gate termio_insert(termio_data_t *td, int c)
17217c478bd9Sstevel@tonic-gate {
17227c478bd9Sstevel@tonic-gate size_t olen = td->tio_cmdbuf.cmd_buflen;
17237c478bd9Sstevel@tonic-gate
17247c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_insert(&td->tio_cmdbuf, c) == 0) {
17257c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_atend(&td->tio_cmdbuf))
17267c478bd9Sstevel@tonic-gate termio_addch(td, c, td->tio_cmdbuf.cmd_buflen - olen);
17277c478bd9Sstevel@tonic-gate else
17287c478bd9Sstevel@tonic-gate termio_insch(td, c, td->tio_cmdbuf.cmd_buflen - olen);
17297c478bd9Sstevel@tonic-gate }
17307c478bd9Sstevel@tonic-gate
17317c478bd9Sstevel@tonic-gate return (NULL);
17327c478bd9Sstevel@tonic-gate }
17337c478bd9Sstevel@tonic-gate
17347c478bd9Sstevel@tonic-gate static const char *
termio_accept(termio_data_t * td,int c)17357c478bd9Sstevel@tonic-gate termio_accept(termio_data_t *td, int c)
17367c478bd9Sstevel@tonic-gate {
17377c478bd9Sstevel@tonic-gate if (td->tio_flags & TIO_FINDHIST) {
17387c478bd9Sstevel@tonic-gate (void) mdb_cmdbuf_findhist(&td->tio_cmdbuf, c);
17397c478bd9Sstevel@tonic-gate
17407c478bd9Sstevel@tonic-gate td->tio_prompt = mdb.m_prompt;
17417c478bd9Sstevel@tonic-gate td->tio_promptlen = mdb.m_promptlen;
17427c478bd9Sstevel@tonic-gate td->tio_flags &= ~TIO_FINDHIST;
17437c478bd9Sstevel@tonic-gate
17447c478bd9Sstevel@tonic-gate termio_redraw(td);
17457c478bd9Sstevel@tonic-gate return (NULL);
17467c478bd9Sstevel@tonic-gate }
17477c478bd9Sstevel@tonic-gate
17487c478bd9Sstevel@tonic-gate /* Ensure that the cursor is at the end of the line */
17497c478bd9Sstevel@tonic-gate (void) termio_end(td, c);
17507c478bd9Sstevel@tonic-gate
17517c478bd9Sstevel@tonic-gate return (mdb_cmdbuf_accept(&td->tio_cmdbuf));
17527c478bd9Sstevel@tonic-gate }
17537c478bd9Sstevel@tonic-gate
17547c478bd9Sstevel@tonic-gate static const char *
termio_backspace(termio_data_t * td,int c)17557c478bd9Sstevel@tonic-gate termio_backspace(termio_data_t *td, int c)
17567c478bd9Sstevel@tonic-gate {
17577c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_backspace(&td->tio_cmdbuf, c) == 0) {
17587c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_atend(&td->tio_cmdbuf))
17597c478bd9Sstevel@tonic-gate termio_bspch(td);
17607c478bd9Sstevel@tonic-gate else
17617c478bd9Sstevel@tonic-gate termio_redraw(td);
17627c478bd9Sstevel@tonic-gate }
17637c478bd9Sstevel@tonic-gate
17647c478bd9Sstevel@tonic-gate return (NULL);
17657c478bd9Sstevel@tonic-gate }
17667c478bd9Sstevel@tonic-gate
17673b6e0a59SMatt Amdur /*
17683b6e0a59SMatt Amdur * This function may end up calling termio_read recursively as part of invoking
17693b6e0a59SMatt Amdur * the mdb pager. To work around this fact, we need to go through and make sure
17703b6e0a59SMatt Amdur * that we change the underlying terminal settings before and after this
17713b6e0a59SMatt Amdur * function call. If we don't do this, we invoke the pager, and don't abort
17723b6e0a59SMatt Amdur * (which will longjmp us elsewhere) we're going to return to the read loop with
17733b6e0a59SMatt Amdur * the wrong termio settings.
17743b6e0a59SMatt Amdur *
17753b6e0a59SMatt Amdur * Furthermore, because of the fact that we're being invoked in a user context
17763b6e0a59SMatt Amdur * that allows us to be interrupted, we need to actually allocate the memory
17773b6e0a59SMatt Amdur * that we're using with GC so that it gets cleaned up in case of the pager
17783b6e0a59SMatt Amdur * resetting us and never reaching the end.
17793b6e0a59SMatt Amdur */
17803b6e0a59SMatt Amdur /*ARGSUSED*/
17813b6e0a59SMatt Amdur static const char *
termio_tab(termio_data_t * td,int c)17823b6e0a59SMatt Amdur termio_tab(termio_data_t *td, int c)
17833b6e0a59SMatt Amdur {
17843b6e0a59SMatt Amdur char *buf;
17853b6e0a59SMatt Amdur const char *result;
17863b6e0a59SMatt Amdur int nres;
17873b6e0a59SMatt Amdur mdb_tab_cookie_t *mtp;
17883b6e0a59SMatt Amdur
17893b6e0a59SMatt Amdur if (termio_ctl(td->tio_io, TCSETSW, &td->tio_dtios) == -1)
17903b6e0a59SMatt Amdur warn("failed to restore terminal attributes");
17913b6e0a59SMatt Amdur
17923b6e0a59SMatt Amdur buf = mdb_alloc(td->tio_cmdbuf.cmd_bufidx + 1, UM_SLEEP | UM_GC);
17933b6e0a59SMatt Amdur (void) strncpy(buf, td->tio_cmdbuf.cmd_buf, td->tio_cmdbuf.cmd_bufidx);
17943b6e0a59SMatt Amdur buf[td->tio_cmdbuf.cmd_bufidx] = '\0';
17953b6e0a59SMatt Amdur td->tio_flags |= TIO_TAB;
17963b6e0a59SMatt Amdur mtp = mdb_tab_init();
17973b6e0a59SMatt Amdur nres = mdb_tab_command(mtp, buf);
17983b6e0a59SMatt Amdur
17993b6e0a59SMatt Amdur if (nres == 0) {
18003b6e0a59SMatt Amdur result = NULL;
18013b6e0a59SMatt Amdur } else {
18023b6e0a59SMatt Amdur result = mdb_tab_match(mtp);
18033b6e0a59SMatt Amdur if (nres != 1) {
18043b6e0a59SMatt Amdur mdb_printf("\n");
18053b6e0a59SMatt Amdur mdb_tab_print(mtp);
18063b6e0a59SMatt Amdur }
18073b6e0a59SMatt Amdur }
18083b6e0a59SMatt Amdur
18093b6e0a59SMatt Amdur if (result != NULL) {
18103b6e0a59SMatt Amdur int index = 0;
18113b6e0a59SMatt Amdur
18123b6e0a59SMatt Amdur while (result[index] != '\0') {
18133b6e0a59SMatt Amdur (void) termio_insert(td, result[index]);
18143b6e0a59SMatt Amdur index++;
18153b6e0a59SMatt Amdur }
18163b6e0a59SMatt Amdur }
18173b6e0a59SMatt Amdur
18183b6e0a59SMatt Amdur termio_redraw(td);
18193b6e0a59SMatt Amdur mdb_tab_fini(mtp);
18203b6e0a59SMatt Amdur td->tio_flags &= ~TIO_TAB;
18213b6e0a59SMatt Amdur if (termio_ctl(td->tio_io, TCSETSW, &td->tio_rtios) == -1)
18223b6e0a59SMatt Amdur warn("failed to set terminal attributes");
18233b6e0a59SMatt Amdur
18243b6e0a59SMatt Amdur
18253b6e0a59SMatt Amdur return (NULL);
18263b6e0a59SMatt Amdur }
18273b6e0a59SMatt Amdur
18287c478bd9Sstevel@tonic-gate static const char *
termio_delchar(termio_data_t * td,int c)18297c478bd9Sstevel@tonic-gate termio_delchar(termio_data_t *td, int c)
18307c478bd9Sstevel@tonic-gate {
18317c478bd9Sstevel@tonic-gate if (!(mdb.m_flags & MDB_FL_IGNEOF) &&
18327c478bd9Sstevel@tonic-gate mdb_cmdbuf_atend(&td->tio_cmdbuf) &&
18337c478bd9Sstevel@tonic-gate mdb_cmdbuf_atstart(&td->tio_cmdbuf))
18347c478bd9Sstevel@tonic-gate return (termio_quit(td, c));
18357c478bd9Sstevel@tonic-gate
18367c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_delchar(&td->tio_cmdbuf, c) == 0) {
18377c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_atend(&td->tio_cmdbuf))
18387c478bd9Sstevel@tonic-gate termio_delch(td);
18397c478bd9Sstevel@tonic-gate else
18407c478bd9Sstevel@tonic-gate termio_redraw(td);
18417c478bd9Sstevel@tonic-gate }
18427c478bd9Sstevel@tonic-gate
18437c478bd9Sstevel@tonic-gate return (NULL);
18447c478bd9Sstevel@tonic-gate }
18457c478bd9Sstevel@tonic-gate
18467c478bd9Sstevel@tonic-gate static const char *
termio_fwdchar(termio_data_t * td,int c)18477c478bd9Sstevel@tonic-gate termio_fwdchar(termio_data_t *td, int c)
18487c478bd9Sstevel@tonic-gate {
18497c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_fwdchar(&td->tio_cmdbuf, c) == 0)
18507c478bd9Sstevel@tonic-gate termio_mvcur(td);
18517c478bd9Sstevel@tonic-gate
18527c478bd9Sstevel@tonic-gate return (NULL);
18537c478bd9Sstevel@tonic-gate }
18547c478bd9Sstevel@tonic-gate
18557c478bd9Sstevel@tonic-gate static const char *
termio_backchar(termio_data_t * td,int c)18567c478bd9Sstevel@tonic-gate termio_backchar(termio_data_t *td, int c)
18577c478bd9Sstevel@tonic-gate {
18587c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_backchar(&td->tio_cmdbuf, c) == 0)
18597c478bd9Sstevel@tonic-gate termio_mvcur(td);
18607c478bd9Sstevel@tonic-gate
18617c478bd9Sstevel@tonic-gate return (NULL);
18627c478bd9Sstevel@tonic-gate }
18637c478bd9Sstevel@tonic-gate
18647c478bd9Sstevel@tonic-gate static const char *
termio_transpose(termio_data_t * td,int c)18657c478bd9Sstevel@tonic-gate termio_transpose(termio_data_t *td, int c)
18667c478bd9Sstevel@tonic-gate {
18677c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_transpose(&td->tio_cmdbuf, c) == 0)
18687c478bd9Sstevel@tonic-gate termio_redraw(td);
18697c478bd9Sstevel@tonic-gate
18707c478bd9Sstevel@tonic-gate return (NULL);
18717c478bd9Sstevel@tonic-gate }
18727c478bd9Sstevel@tonic-gate
18737c478bd9Sstevel@tonic-gate static const char *
termio_home(termio_data_t * td,int c)18747c478bd9Sstevel@tonic-gate termio_home(termio_data_t *td, int c)
18757c478bd9Sstevel@tonic-gate {
18767c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_home(&td->tio_cmdbuf, c) == 0)
18777c478bd9Sstevel@tonic-gate termio_mvcur(td);
18787c478bd9Sstevel@tonic-gate
18797c478bd9Sstevel@tonic-gate return (NULL);
18807c478bd9Sstevel@tonic-gate }
18817c478bd9Sstevel@tonic-gate
18827c478bd9Sstevel@tonic-gate static const char *
termio_end(termio_data_t * td,int c)18837c478bd9Sstevel@tonic-gate termio_end(termio_data_t *td, int c)
18847c478bd9Sstevel@tonic-gate {
18857c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_end(&td->tio_cmdbuf, c) == 0)
18867c478bd9Sstevel@tonic-gate termio_mvcur(td);
18877c478bd9Sstevel@tonic-gate
18887c478bd9Sstevel@tonic-gate return (NULL);
18897c478bd9Sstevel@tonic-gate }
18907c478bd9Sstevel@tonic-gate
18917c478bd9Sstevel@tonic-gate static const char *
termio_fwdword(termio_data_t * td,int c)18927c478bd9Sstevel@tonic-gate termio_fwdword(termio_data_t *td, int c)
18937c478bd9Sstevel@tonic-gate {
18947c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_fwdword(&td->tio_cmdbuf, c) == 0)
18957c478bd9Sstevel@tonic-gate termio_mvcur(td);
18967c478bd9Sstevel@tonic-gate
18977c478bd9Sstevel@tonic-gate return (NULL);
18987c478bd9Sstevel@tonic-gate }
18997c478bd9Sstevel@tonic-gate
19007c478bd9Sstevel@tonic-gate static const char *
termio_backword(termio_data_t * td,int c)19017c478bd9Sstevel@tonic-gate termio_backword(termio_data_t *td, int c)
19027c478bd9Sstevel@tonic-gate {
19037c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_backword(&td->tio_cmdbuf, c) == 0)
19047c478bd9Sstevel@tonic-gate termio_mvcur(td);
19057c478bd9Sstevel@tonic-gate
19067c478bd9Sstevel@tonic-gate return (NULL);
19077c478bd9Sstevel@tonic-gate }
19087c478bd9Sstevel@tonic-gate
19097c478bd9Sstevel@tonic-gate static const char *
termio_kill(termio_data_t * td,int c)19107c478bd9Sstevel@tonic-gate termio_kill(termio_data_t *td, int c)
19117c478bd9Sstevel@tonic-gate {
19127c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_kill(&td->tio_cmdbuf, c) == 0)
19137c478bd9Sstevel@tonic-gate termio_redraw(td);
19147c478bd9Sstevel@tonic-gate
19157c478bd9Sstevel@tonic-gate return (NULL);
19167c478bd9Sstevel@tonic-gate }
19177c478bd9Sstevel@tonic-gate
19187c478bd9Sstevel@tonic-gate static const char *
termio_killfwdword(termio_data_t * td,int c)19197c478bd9Sstevel@tonic-gate termio_killfwdword(termio_data_t *td, int c)
19207c478bd9Sstevel@tonic-gate {
19217c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_killfwdword(&td->tio_cmdbuf, c) == 0)
19227c478bd9Sstevel@tonic-gate termio_redraw(td);
19237c478bd9Sstevel@tonic-gate
19247c478bd9Sstevel@tonic-gate return (NULL);
19257c478bd9Sstevel@tonic-gate }
19267c478bd9Sstevel@tonic-gate
19277c478bd9Sstevel@tonic-gate static const char *
termio_killbackword(termio_data_t * td,int c)19287c478bd9Sstevel@tonic-gate termio_killbackword(termio_data_t *td, int c)
19297c478bd9Sstevel@tonic-gate {
19307c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_killbackword(&td->tio_cmdbuf, c) == 0)
19317c478bd9Sstevel@tonic-gate termio_redraw(td);
19327c478bd9Sstevel@tonic-gate
19337c478bd9Sstevel@tonic-gate return (NULL);
19347c478bd9Sstevel@tonic-gate }
19357c478bd9Sstevel@tonic-gate
19367c478bd9Sstevel@tonic-gate static const char *
termio_reset(termio_data_t * td,int c)19377c478bd9Sstevel@tonic-gate termio_reset(termio_data_t *td, int c)
19387c478bd9Sstevel@tonic-gate {
19397c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_reset(&td->tio_cmdbuf, c) == 0)
19407c478bd9Sstevel@tonic-gate termio_clear(td);
19417c478bd9Sstevel@tonic-gate
19427c478bd9Sstevel@tonic-gate return (NULL);
19437c478bd9Sstevel@tonic-gate }
19447c478bd9Sstevel@tonic-gate
19457c478bd9Sstevel@tonic-gate /*ARGSUSED*/
19467c478bd9Sstevel@tonic-gate static const char *
termio_widescreen(termio_data_t * td,int c)19477c478bd9Sstevel@tonic-gate termio_widescreen(termio_data_t *td, int c)
19487c478bd9Sstevel@tonic-gate {
19497c478bd9Sstevel@tonic-gate if (td->tio_flags & TIO_XTERM) {
19507c478bd9Sstevel@tonic-gate if (td->tio_cols == 80)
19517c478bd9Sstevel@tonic-gate termio_tput(td, TI_DECSET(TI_DECCOLM), 1);
19527c478bd9Sstevel@tonic-gate else
19537c478bd9Sstevel@tonic-gate termio_tput(td, TI_DECRST(TI_DECCOLM), 1);
19547c478bd9Sstevel@tonic-gate mdb_iob_flush(td->tio_out);
19557c478bd9Sstevel@tonic-gate termio_winch(SIGWINCH, NULL, NULL, td);
19567c478bd9Sstevel@tonic-gate }
19577c478bd9Sstevel@tonic-gate
19587c478bd9Sstevel@tonic-gate return (NULL);
19597c478bd9Sstevel@tonic-gate }
19607c478bd9Sstevel@tonic-gate
19617c478bd9Sstevel@tonic-gate static const char *
termio_prevhist(termio_data_t * td,int c)19627c478bd9Sstevel@tonic-gate termio_prevhist(termio_data_t *td, int c)
19637c478bd9Sstevel@tonic-gate {
19647c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_prevhist(&td->tio_cmdbuf, c) == 0)
19657c478bd9Sstevel@tonic-gate termio_redraw(td);
19667c478bd9Sstevel@tonic-gate
19677c478bd9Sstevel@tonic-gate return (NULL);
19687c478bd9Sstevel@tonic-gate }
19697c478bd9Sstevel@tonic-gate
19707c478bd9Sstevel@tonic-gate static const char *
termio_nexthist(termio_data_t * td,int c)19717c478bd9Sstevel@tonic-gate termio_nexthist(termio_data_t *td, int c)
19727c478bd9Sstevel@tonic-gate {
19737c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_nexthist(&td->tio_cmdbuf, c) == 0)
19747c478bd9Sstevel@tonic-gate termio_redraw(td);
19757c478bd9Sstevel@tonic-gate
19767c478bd9Sstevel@tonic-gate return (NULL);
19777c478bd9Sstevel@tonic-gate }
19787c478bd9Sstevel@tonic-gate
19797c478bd9Sstevel@tonic-gate /*
19807c478bd9Sstevel@tonic-gate * Single-key accelerator support. Several commands are so commonly used as to
19817c478bd9Sstevel@tonic-gate * require a single-key equivalent. If we see one of these accelerator
19827c478bd9Sstevel@tonic-gate * characters at the beginning of an otherwise-empty line, we'll replace it with
19837c478bd9Sstevel@tonic-gate * the expansion.
19847c478bd9Sstevel@tonic-gate */
19857c478bd9Sstevel@tonic-gate static const char *
termio_accel(termio_data_t * td,int c)19867c478bd9Sstevel@tonic-gate termio_accel(termio_data_t *td, int c)
19877c478bd9Sstevel@tonic-gate {
19887c478bd9Sstevel@tonic-gate const char *p;
19897c478bd9Sstevel@tonic-gate
19907c478bd9Sstevel@tonic-gate if (td->tio_cmdbuf.cmd_buflen != 0 ||
19917c478bd9Sstevel@tonic-gate (p = termio_accel_lookup(c)) == NULL)
19927c478bd9Sstevel@tonic-gate return (termio_insert(td, c));
19937c478bd9Sstevel@tonic-gate
19947c478bd9Sstevel@tonic-gate while (*p != '\0')
19957c478bd9Sstevel@tonic-gate (void) termio_insert(td, *p++);
19967c478bd9Sstevel@tonic-gate return (termio_accept(td, '\n'));
19977c478bd9Sstevel@tonic-gate }
19987c478bd9Sstevel@tonic-gate
19997c478bd9Sstevel@tonic-gate static const char *
termio_findhist(termio_data_t * td,int c)20007c478bd9Sstevel@tonic-gate termio_findhist(termio_data_t *td, int c)
20017c478bd9Sstevel@tonic-gate {
20027c478bd9Sstevel@tonic-gate if (mdb_cmdbuf_reset(&td->tio_cmdbuf, c) == 0) {
20037c478bd9Sstevel@tonic-gate td->tio_prompt = "Search: ";
20047c478bd9Sstevel@tonic-gate td->tio_promptlen = strlen(td->tio_prompt);
20057c478bd9Sstevel@tonic-gate td->tio_flags |= TIO_FINDHIST;
20067c478bd9Sstevel@tonic-gate termio_redraw(td);
20077c478bd9Sstevel@tonic-gate }
20087c478bd9Sstevel@tonic-gate
20097c478bd9Sstevel@tonic-gate return (NULL);
20107c478bd9Sstevel@tonic-gate }
20117c478bd9Sstevel@tonic-gate
20127c478bd9Sstevel@tonic-gate /*ARGSUSED*/
20137c478bd9Sstevel@tonic-gate static const char *
termio_refresh(termio_data_t * td,int c)20147c478bd9Sstevel@tonic-gate termio_refresh(termio_data_t *td, int c)
20157c478bd9Sstevel@tonic-gate {
20167c478bd9Sstevel@tonic-gate if (td->tio_info.ti_clear.at_str) {
20177c478bd9Sstevel@tonic-gate termio_tput(td, td->tio_info.ti_clear.at_str, 1);
20187c478bd9Sstevel@tonic-gate td->tio_x = td->tio_y = 0;
20197c478bd9Sstevel@tonic-gate }
20207c478bd9Sstevel@tonic-gate termio_redraw(td);
20217c478bd9Sstevel@tonic-gate return (NULL);
20227c478bd9Sstevel@tonic-gate }
20237c478bd9Sstevel@tonic-gate
20247c478bd9Sstevel@tonic-gate /*
20257c478bd9Sstevel@tonic-gate * Leave the terminal read code by longjmp'ing up the stack of mdb_frame_t's
20267c478bd9Sstevel@tonic-gate * back to the main parsing loop (see mdb_run() in mdb.c).
20277c478bd9Sstevel@tonic-gate */
20287c478bd9Sstevel@tonic-gate static const char *
termio_abort(termio_data_t * td,int c,int err)20297c478bd9Sstevel@tonic-gate termio_abort(termio_data_t *td, int c, int err)
20307c478bd9Sstevel@tonic-gate {
20317c478bd9Sstevel@tonic-gate (void) mdb_cmdbuf_reset(&td->tio_cmdbuf, c);
20327c478bd9Sstevel@tonic-gate td->tio_active = FALSE;
20337c478bd9Sstevel@tonic-gate td->tio_rti_on = FALSE;
20347c478bd9Sstevel@tonic-gate
20357c478bd9Sstevel@tonic-gate if (termio_ctl(td->tio_io, TCSETSW, &td->tio_dtios) == -1)
20367c478bd9Sstevel@tonic-gate warn("failed to restore terminal attributes");
20377c478bd9Sstevel@tonic-gate
20387c478bd9Sstevel@tonic-gate longjmp(mdb.m_frame->f_pcb, err);
20397c478bd9Sstevel@tonic-gate /*NOTREACHED*/
20407c478bd9Sstevel@tonic-gate return (NULL);
20417c478bd9Sstevel@tonic-gate }
20427c478bd9Sstevel@tonic-gate
20437c478bd9Sstevel@tonic-gate static const char *
termio_intr(termio_data_t * td,int c)20447c478bd9Sstevel@tonic-gate termio_intr(termio_data_t *td, int c)
20457c478bd9Sstevel@tonic-gate {
20467c478bd9Sstevel@tonic-gate return (termio_abort(td, c, MDB_ERR_SIGINT));
20477c478bd9Sstevel@tonic-gate }
20487c478bd9Sstevel@tonic-gate
20497c478bd9Sstevel@tonic-gate static const char *
termio_quit(termio_data_t * td,int c)20507c478bd9Sstevel@tonic-gate termio_quit(termio_data_t *td, int c)
20517c478bd9Sstevel@tonic-gate {
20527c478bd9Sstevel@tonic-gate return (termio_abort(td, c, MDB_ERR_QUIT));
20537c478bd9Sstevel@tonic-gate }
20547c478bd9Sstevel@tonic-gate
20557c478bd9Sstevel@tonic-gate /*ARGSUSED*/
20567c478bd9Sstevel@tonic-gate static const char *
termio_susp(termio_data_t * td,int c)20577c478bd9Sstevel@tonic-gate termio_susp(termio_data_t *td, int c)
20587c478bd9Sstevel@tonic-gate {
2059*30699046SRichard Lowe (void) mdb_signal_sethandler(SIGWINCH, MDB_SIG_IGN, NULL);
2060*30699046SRichard Lowe (void) mdb_signal_sethandler(SIGTSTP, MDB_SIG_IGN, NULL);
20617c478bd9Sstevel@tonic-gate
20627c478bd9Sstevel@tonic-gate termio_suspend_tty(td, &td->tio_ptios);
20637c478bd9Sstevel@tonic-gate mdb_iob_nl(td->tio_out);
20647c478bd9Sstevel@tonic-gate
2065*30699046SRichard Lowe (void) mdb_signal_sethandler(SIGTSTP, MDB_SIG_DFL, NULL);
20667c478bd9Sstevel@tonic-gate (void) mdb_signal_pgrp(SIGTSTP);
20677c478bd9Sstevel@tonic-gate
20687c478bd9Sstevel@tonic-gate /*
20697c478bd9Sstevel@tonic-gate * When we call mdb_signal_pgrp(SIGTSTP), we are expecting the entire
20707c478bd9Sstevel@tonic-gate * debugger process group to be stopped by the kernel. Once we return
20717c478bd9Sstevel@tonic-gate * from that call, we assume we are resuming from a subsequent SIGCONT.
20727c478bd9Sstevel@tonic-gate */
2073*30699046SRichard Lowe (void) mdb_signal_sethandler(SIGTSTP, MDB_SIG_IGN, NULL);
20747c478bd9Sstevel@tonic-gate termio_resume_tty(td, &td->tio_ptios);
20757c478bd9Sstevel@tonic-gate
20767c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGWINCH, termio_winch, td);
20777c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGTSTP, termio_tstp, td);
20787c478bd9Sstevel@tonic-gate
20797c478bd9Sstevel@tonic-gate if (td->tio_active)
20807c478bd9Sstevel@tonic-gate siglongjmp(td->tio_env, SIGCONT);
20817c478bd9Sstevel@tonic-gate
20827c478bd9Sstevel@tonic-gate return (NULL);
20837c478bd9Sstevel@tonic-gate }
20847c478bd9Sstevel@tonic-gate
20857c478bd9Sstevel@tonic-gate /*ARGSUSED*/
20867c478bd9Sstevel@tonic-gate static void
termio_winch(int sig,siginfo_t * sip,ucontext_t * ucp,void * data)20877c478bd9Sstevel@tonic-gate termio_winch(int sig, siginfo_t *sip, ucontext_t *ucp, void *data)
20887c478bd9Sstevel@tonic-gate {
20897c478bd9Sstevel@tonic-gate termio_data_t *td = data;
20907c478bd9Sstevel@tonic-gate mdb_bool_t change = FALSE;
20917c478bd9Sstevel@tonic-gate struct winsize winsz;
20927c478bd9Sstevel@tonic-gate
20937c478bd9Sstevel@tonic-gate if (termio_ctl(td->tio_io, TIOCGWINSZ, &winsz) == -1)
20947c478bd9Sstevel@tonic-gate return; /* just ignore this WINCH if the ioctl fails */
20957c478bd9Sstevel@tonic-gate
20967c478bd9Sstevel@tonic-gate if (td->tio_rows != (size_t)winsz.ws_row ||
20977c478bd9Sstevel@tonic-gate td->tio_cols != (size_t)winsz.ws_col) {
20987c478bd9Sstevel@tonic-gate
20997c478bd9Sstevel@tonic-gate if (td->tio_active)
21007c478bd9Sstevel@tonic-gate termio_clear(td);
21017c478bd9Sstevel@tonic-gate
21027c478bd9Sstevel@tonic-gate if (winsz.ws_row != 0)
21037c478bd9Sstevel@tonic-gate td->tio_rows = (size_t)winsz.ws_row;
21047c478bd9Sstevel@tonic-gate
21057c478bd9Sstevel@tonic-gate if (winsz.ws_col != 0)
21067c478bd9Sstevel@tonic-gate td->tio_cols = (size_t)winsz.ws_col;
21077c478bd9Sstevel@tonic-gate
21087c478bd9Sstevel@tonic-gate if (td->tio_active)
21097c478bd9Sstevel@tonic-gate termio_clear(td);
21107c478bd9Sstevel@tonic-gate
21117c478bd9Sstevel@tonic-gate mdb_iob_resize(td->tio_out, td->tio_rows, td->tio_cols);
21127c478bd9Sstevel@tonic-gate change = TRUE;
21137c478bd9Sstevel@tonic-gate }
21147c478bd9Sstevel@tonic-gate
21157c478bd9Sstevel@tonic-gate if (change && td->tio_active)
21167c478bd9Sstevel@tonic-gate siglongjmp(td->tio_env, sig);
21177c478bd9Sstevel@tonic-gate
21187c478bd9Sstevel@tonic-gate if (change && td->tio_link != NULL)
21197c478bd9Sstevel@tonic-gate mdb_iob_resize(td->tio_link, td->tio_rows, td->tio_cols);
21207c478bd9Sstevel@tonic-gate }
21217c478bd9Sstevel@tonic-gate
21227c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21237c478bd9Sstevel@tonic-gate static void
termio_tstp(int sig,siginfo_t * sip,ucontext_t * ucp,void * data)21247c478bd9Sstevel@tonic-gate termio_tstp(int sig, siginfo_t *sip, ucontext_t *ucp, void *data)
21257c478bd9Sstevel@tonic-gate {
21267c478bd9Sstevel@tonic-gate (void) termio_susp(data, CTRL('Z'));
21277c478bd9Sstevel@tonic-gate }
2128