[BACK]Return to reset_cmd.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tic

File: [local] / src / usr.bin / tic / reset_cmd.c (download)

Revision 1.1, Tue Oct 17 09:52:10 2023 UTC (7 months ago) by nicm
Branch: MAIN
CVS Tags: OPENBSD_7_5_BASE, OPENBSD_7_5, HEAD

Update ncurses and associated libraries (form, panel, menu) to
6.4-20230826 (from 5.7-20081102).

Based on result from Thomas Dickey's ncu2openbsd script and then
modified. Switches to the upstream tput. Major bump for the ncurses
libraries and for libedit and libreadline.

Help from tb, millert.

ok deraadt sthen

/****************************************************************************
 * Copyright 2019-2021,2023 Thomas E. Dickey                                *
 * Copyright 2016,2017 Free Software Foundation, Inc.                       *
 *                                                                          *
 * Permission is hereby granted, free of charge, to any person obtaining a  *
 * copy of this software and associated documentation files (the            *
 * "Software"), to deal in the Software without restriction, including      *
 * without limitation the rights to use, copy, modify, merge, publish,      *
 * distribute, distribute with modifications, sublicense, and/or sell       *
 * copies of the Software, and to permit persons to whom the Software is    *
 * furnished to do so, subject to the following conditions:                 *
 *                                                                          *
 * The above copyright notice and this permission notice shall be included  *
 * in all copies or substantial portions of the Software.                   *
 *                                                                          *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
 *                                                                          *
 * Except as contained in this notice, the name(s) of the above copyright   *
 * holders shall not be used in advertising or otherwise to promote the     *
 * sale, use or other dealings in this Software without prior written       *
 * authorization.                                                           *
 ****************************************************************************/

/****************************************************************************
 *  Author: Thomas E. Dickey                                                *
 ****************************************************************************/

#include <reset_cmd.h>
#include <tty_settings.h>

#include <errno.h>
#include <stdio.h>
#include <fcntl.h>

#if HAVE_SIZECHANGE
# if !defined(sun) || !TERMIOS
#  if HAVE_SYS_IOCTL_H
#   include <sys/ioctl.h>
#  endif
# endif
#endif

#if NEED_PTEM_H
/* they neglected to define struct winsize in termios.h -- it is only
   in termio.h	*/
#include <sys/stream.h>
#include <sys/ptem.h>
#endif

MODULE_ID("$Id: reset_cmd.c,v 1.1 2023/10/17 09:52:10 nicm Exp $")

/*
 * SCO defines TIOCGSIZE and the corresponding struct.  Other systems (SunOS,
 * Solaris, IRIX) define TIOCGWINSZ and struct winsize.
 */
#ifdef TIOCGSIZE
# define IOCTL_GET_WINSIZE TIOCGSIZE
# define IOCTL_SET_WINSIZE TIOCSSIZE
# define STRUCT_WINSIZE struct ttysize
# define WINSIZE_ROWS(n) n.ts_lines
# define WINSIZE_COLS(n) n.ts_cols
#else
# ifdef TIOCGWINSZ
#  define IOCTL_GET_WINSIZE TIOCGWINSZ
#  define IOCTL_SET_WINSIZE TIOCSWINSZ
#  define STRUCT_WINSIZE struct winsize
#  define WINSIZE_ROWS(n) n.ws_row
#  define WINSIZE_COLS(n) n.ws_col
# endif
#endif

static FILE *my_file;

static bool use_reset = FALSE;	/* invoked as reset */
static bool use_init = FALSE;	/* invoked as init */

static GCC_NORETURN void
failed(const char *msg)
{
    int code = errno;

    (void) fprintf(stderr, "%s: %s: %s\n", _nc_progname, msg, strerror(code));
    restore_tty_settings();
    (void) fprintf(my_file, "\n");
    fflush(my_file);
    ExitProgram(ErrSystem(code));
    /* NOTREACHED */
}

static bool
cat_file(char *file)
{
    FILE *fp;
    size_t nr;
    char buf[BUFSIZ];
    bool sent = FALSE;

    if (file != 0) {
	if ((fp = safe_fopen(file, "r")) == 0)
	    failed(file);

	while ((nr = fread(buf, sizeof(char), sizeof(buf), fp)) != 0) {
	    if (fwrite(buf, sizeof(char), nr, my_file) != nr) {
		failed(file);
	    }
	    sent = TRUE;
	}
	fclose(fp);
    }
    return sent;
}

static int
out_char(int c)
{
    return putc(c, my_file);
}

/**************************************************************************
 * Mode-setting logic
 **************************************************************************/

/* some BSD systems have these built in, some systems are missing
 * one or more definitions. The safest solution is to override unless the
 * commonly-altered ones are defined.
 */
#if !(defined(CERASE) && defined(CINTR) && defined(CKILL) && defined(CQUIT))
#undef CEOF
#undef CERASE
#undef CINTR
#undef CKILL
#undef CLNEXT
#undef CRPRNT
#undef CQUIT
#undef CSTART
#undef CSTOP
#undef CSUSP
#endif

/* control-character defaults */
#ifndef CEOF
#define CEOF	CTRL('D')
#endif
#ifndef CERASE
#define CERASE	CTRL('H')
#endif
#ifndef CINTR
#define CINTR	127		/* ^? */
#endif
#ifndef CKILL
#define CKILL	CTRL('U')
#endif
#ifndef CLNEXT
#define CLNEXT  CTRL('v')
#endif
#ifndef CRPRNT
#define CRPRNT  CTRL('r')
#endif
#ifndef CQUIT
#define CQUIT	CTRL('\\')
#endif
#ifndef CSTART
#define CSTART	CTRL('Q')
#endif
#ifndef CSTOP
#define CSTOP	CTRL('S')
#endif
#ifndef CSUSP
#define CSUSP	CTRL('Z')
#endif

#if defined(_POSIX_VDISABLE)
#define DISABLED(val)   (((_POSIX_VDISABLE != -1) \
		       && ((val) == _POSIX_VDISABLE)) \
		      || ((val) <= 0))
#else
#define DISABLED(val)   ((int)(val) <= 0)
#endif

#define CHK(val, dft)   (unsigned char) (DISABLED(val) ? dft : val)

#define reset_char(item, value) \
    tty_settings->c_cc[item] = CHK(tty_settings->c_cc[item], value)

/*
 * Reset the terminal mode bits to a sensible state.  Very useful after
 * a child program dies in raw mode.
 */
void
reset_tty_settings(int fd, TTY * tty_settings, int noset)
{
    GET_TTY(fd, tty_settings);

#ifdef TERMIOS
#if defined(VDISCARD) && defined(CDISCARD)
    reset_char(VDISCARD, CDISCARD);
#endif
    reset_char(VEOF, CEOF);
    reset_char(VERASE, CERASE);
#if defined(VERASE2) && defined(CERASE2)
    reset_char(VERASE2, CERASE2);
#endif
#if defined(VFLUSH) && defined(CFLUSH)
    reset_char(VFLUSH, CFLUSH);
#endif
    reset_char(VINTR, CINTR);
    reset_char(VKILL, CKILL);
#if defined(VLNEXT) && defined(CLNEXT)
    reset_char(VLNEXT, CLNEXT);
#endif
    reset_char(VQUIT, CQUIT);
#if defined(VREPRINT) && defined(CRPRNT)
    reset_char(VREPRINT, CRPRNT);
#endif
#if defined(VSTART) && defined(CSTART)
    reset_char(VSTART, CSTART);
#endif
#if defined(VSTOP) && defined(CSTOP)
    reset_char(VSTOP, CSTOP);
#endif
#if defined(VSUSP) && defined(CSUSP)
    reset_char(VSUSP, CSUSP);
#endif
#if defined(VWERASE) && defined(CWERASE)
    reset_char(VWERASE, CWERASE);
#endif

    tty_settings->c_iflag &= ~((unsigned) (IGNBRK
					   | PARMRK
					   | INPCK
					   | ISTRIP
					   | INLCR
					   | IGNCR
#ifdef IUCLC
					   | IUCLC
#endif
#ifdef IXANY
					   | IXANY
#endif
					   | IXOFF));

    tty_settings->c_iflag |= (BRKINT
			      | IGNPAR
			      | ICRNL
			      | IXON
#ifdef IMAXBEL
			      | IMAXBEL
#endif
	);

    tty_settings->c_oflag &= ~((unsigned) (0
#ifdef OLCUC
					   | OLCUC
#endif
#ifdef OCRNL
					   | OCRNL
#endif
#ifdef ONOCR
					   | ONOCR
#endif
#ifdef ONLRET
					   | ONLRET
#endif
#ifdef OFILL
					   | OFILL
#endif
#ifdef OFDEL
					   | OFDEL
#endif
#ifdef NLDLY
					   | NLDLY
#endif
#ifdef CRDLY
					   | CRDLY
#endif
#ifdef TABDLY
					   | TABDLY
#endif
#ifdef BSDLY
					   | BSDLY
#endif
#ifdef VTDLY
					   | VTDLY
#endif
#ifdef FFDLY
					   | FFDLY
#endif
			       ));

    tty_settings->c_oflag |= (OPOST
#ifdef ONLCR
			      | ONLCR
#endif
	);

    tty_settings->c_cflag &= ~((unsigned) (CSIZE
					   | CSTOPB
					   | PARENB
					   | PARODD
					   | CLOCAL));
    tty_settings->c_cflag |= (CS8 | CREAD);
    tty_settings->c_lflag &= ~((unsigned) (ECHONL
					   | NOFLSH
#ifdef TOSTOP
					   | TOSTOP
#endif
#ifdef ECHOPTR
					   | ECHOPRT
#endif
#ifdef XCASE
					   | XCASE
#endif
			       ));

    tty_settings->c_lflag |= (ISIG
			      | ICANON
			      | ECHO
			      | ECHOE
			      | ECHOK
#ifdef ECHOCTL
			      | ECHOCTL
#endif
#ifdef ECHOKE
			      | ECHOKE
#endif
	);
#endif

    if (!noset) {
	SET_TTY(fd, tty_settings);
    }
}

/*
 * Returns a "good" value for the erase character.  This is loosely based on
 * the BSD4.4 logic.
 */
static int
default_erase(void)
{
    int result;

    if (over_strike
	&& VALID_STRING(key_backspace)
	&& strlen(key_backspace) == 1) {
	result = key_backspace[0];
    } else {
	result = CERASE;
    }

    return result;
}

/*
 * Update the values of the erase, interrupt, and kill characters in the TTY
 * parameter.
 *
 * SVr4 tset (e.g., Solaris 2.5) only modifies the intr, quit or erase
 * characters if they're unset, or if we specify them as options.  This differs
 * from BSD 4.4 tset, which always sets erase.
 */
void
set_control_chars(TTY * tty_settings, int my_erase, int my_intr, int my_kill)
{
#if defined(EXP_WIN32_DRIVER)
    /* noop */
    (void) tty_settings;
    (void) my_erase;
    (void) my_intr;
    (void) my_kill;
#else
    if (DISABLED(tty_settings->c_cc[VERASE]) || my_erase >= 0) {
	tty_settings->c_cc[VERASE] = UChar((my_erase >= 0)
					   ? my_erase
					   : default_erase());
    }

    if (DISABLED(tty_settings->c_cc[VINTR]) || my_intr >= 0) {
	tty_settings->c_cc[VINTR] = UChar((my_intr >= 0)
					  ? my_intr
					  : CINTR);
    }

    if (DISABLED(tty_settings->c_cc[VKILL]) || my_kill >= 0) {
	tty_settings->c_cc[VKILL] = UChar((my_kill >= 0)
					  ? my_kill
					  : CKILL);
    }
#endif
}

/*
 * Set up various conversions in the TTY parameter, including parity, tabs,
 * returns, echo, and case, according to the termcap entry.
 */
void
set_conversions(TTY * tty_settings)
{
#if defined(EXP_WIN32_DRIVER)
    /* FIXME */
#else
#ifdef ONLCR
    tty_settings->c_oflag |= ONLCR;
#endif
    tty_settings->c_iflag |= ICRNL;
    tty_settings->c_lflag |= ECHO;
#ifdef OXTABS
    tty_settings->c_oflag |= OXTABS;
#endif /* OXTABS */

    /* test used to be tgetflag("NL") */
    if (VALID_STRING(newline) && newline[0] == '\n' && !newline[1]) {
	/* Newline, not linefeed. */
#ifdef ONLCR
	tty_settings->c_oflag &= ~((unsigned) ONLCR);
#endif
	tty_settings->c_iflag &= ~((unsigned) ICRNL);
    }
#ifdef OXTABS
    /* test used to be tgetflag("pt") */
    if (VALID_STRING(set_tab) && VALID_STRING(clear_all_tabs))
	tty_settings->c_oflag &= ~OXTABS;
#endif /* OXTABS */
    tty_settings->c_lflag |= (ECHOE | ECHOK);
#endif
}

static bool
sent_string(const char *s)
{
    bool sent = FALSE;
    if (VALID_STRING(s)) {
	tputs(s, 0, out_char);
	sent = TRUE;
    }
    return sent;
}

static bool
to_left_margin(void)
{
    if (VALID_STRING(carriage_return)) {
	sent_string(carriage_return);
    } else {
	out_char('\r');
    }
    return TRUE;
}

/*
 * Set the hardware tabs on the terminal, using the 'ct' (clear all tabs),
 * 'st' (set one tab) and 'ch' (horizontal cursor addressing) capabilities.
 * This is done before 'if' and 'is', so they can recover in case of error.
 *
 * Return TRUE if we set any tab stops, FALSE if not.
 */
static bool
reset_tabstops(int wide)
{
    if ((init_tabs != 8)
	&& VALID_NUMERIC(init_tabs)
	&& VALID_STRING(set_tab)
	&& VALID_STRING(clear_all_tabs)) {
	int c;

	to_left_margin();
	tputs(clear_all_tabs, 0, out_char);
	if (init_tabs > 1) {
	    if (init_tabs > wide)
		init_tabs = (short) wide;
	    for (c = init_tabs; c < wide; c += init_tabs) {
		fprintf(my_file, "%*s", init_tabs, " ");
		tputs(set_tab, 0, out_char);
	    }
	    to_left_margin();
	}
	return (TRUE);
    }
    return (FALSE);
}

/* Output startup string. */
bool
send_init_strings(int fd GCC_UNUSED, TTY * old_settings)
{
    int i;
    bool need_flush = FALSE;

    (void) old_settings;
#ifdef TAB3
    if (old_settings != 0 &&
	old_settings->c_oflag & (TAB3 | ONLCR | OCRNL | ONLRET)) {
	old_settings->c_oflag &= (TAB3 | ONLCR | OCRNL | ONLRET);
	SET_TTY(fd, old_settings);
    }
#endif
    if (use_reset || use_init) {
	if (VALID_STRING(init_prog)) {
	    IGNORE_RC(system(init_prog));
	}

	need_flush |= sent_string((use_reset && (reset_1string != 0))
				  ? reset_1string
				  : init_1string);

	need_flush |= sent_string((use_reset && (reset_2string != 0))
				  ? reset_2string
				  : init_2string);

	if (VALID_STRING(clear_margins)) {
	    need_flush |= sent_string(clear_margins);
	} else
#if defined(set_lr_margin)
	if (VALID_STRING(set_lr_margin)) {
	    need_flush |= sent_string(TIPARM_2(set_lr_margin, 0, columns - 1));
	} else
#endif
#if defined(set_left_margin_parm) && defined(set_right_margin_parm)
	    if (VALID_STRING(set_left_margin_parm)
		&& VALID_STRING(set_right_margin_parm)) {
	    need_flush |= sent_string(TIPARM_1(set_left_margin_parm, 0));
	    need_flush |= sent_string(TIPARM_1(set_right_margin_parm,
					       columns - 1));
	} else
#endif
	    if (VALID_STRING(set_left_margin)
		&& VALID_STRING(set_right_margin)) {
	    need_flush |= to_left_margin();
	    need_flush |= sent_string(set_left_margin);
	    if (VALID_STRING(parm_right_cursor)) {
		need_flush |= sent_string(TIPARM_1(parm_right_cursor,
						   columns - 1));
	    } else {
		for (i = 0; i < columns - 1; i++) {
		    out_char(' ');
		    need_flush = TRUE;
		}
	    }
	    need_flush |= sent_string(set_right_margin);
	    need_flush |= to_left_margin();
	}

	need_flush |= reset_tabstops(columns);

	need_flush |= cat_file((use_reset && reset_file) ? reset_file : init_file);

	need_flush |= sent_string((use_reset && (reset_3string != 0))
				  ? reset_3string
				  : init_3string);
    }

    return need_flush;
}

/*
 * Tell the user if a control key has been changed from the default value.
 */
static void
show_tty_change(TTY * old_settings,
		TTY * new_settings,
		const char *name,
		int which,
		unsigned def)
{
    unsigned older = 0, newer = 0;
    char *p;

#if defined(EXP_WIN32_DRIVER)
    /* noop */
    (void) old_settings;
    (void) new_settings;
    (void) name;
    (void) which;
    (void) def;
#else
    newer = new_settings->c_cc[which];
    older = old_settings->c_cc[which];

    if (older == newer && older == def)
	return;
#endif
    (void) fprintf(stderr, "%s %s ", name, older == newer ? "is" : "set to");

    if (DISABLED(newer)) {
	(void) fprintf(stderr, "undef.\n");
	/*
	 * Check 'delete' before 'backspace', since the key_backspace value
	 * is ambiguous.
	 */
    } else if (newer == 0177) {
	(void) fprintf(stderr, "delete.\n");
    } else if ((p = key_backspace) != 0
	       && newer == (unsigned char) p[0]
	       && p[1] == '\0') {
	(void) fprintf(stderr, "backspace.\n");
    } else if (newer < 040) {
	newer ^= 0100;
	(void) fprintf(stderr, "control-%c (^%c).\n", UChar(newer), UChar(newer));
    } else
	(void) fprintf(stderr, "%c.\n", UChar(newer));
}

/**************************************************************************
 * Miscellaneous.
 **************************************************************************/

void
reset_start(FILE *fp, bool is_reset, bool is_init)
{
    my_file = fp;
    use_reset = is_reset;
    use_init = is_init;
}

void
reset_flush(void)
{
    if (my_file != 0)
	fflush(my_file);
}

void
print_tty_chars(TTY * old_settings, TTY * new_settings)
{
#if defined(EXP_WIN32_DRIVER)
    /* noop */
#else
    show_tty_change(old_settings, new_settings, "Erase", VERASE, CERASE);
    show_tty_change(old_settings, new_settings, "Kill", VKILL, CKILL);
    show_tty_change(old_settings, new_settings, "Interrupt", VINTR, CINTR);
#endif
}

#if HAVE_SIZECHANGE
/*
 * Set window size if not set already, but update our copy of the values if the
 * size was set.
 */
void
set_window_size(int fd, short *high, short *wide)
{
    STRUCT_WINSIZE win;
    (void) ioctl(fd, IOCTL_GET_WINSIZE, &win);
    if (WINSIZE_ROWS(win) == 0 &&
	WINSIZE_COLS(win) == 0) {
	if (*high > 0 && *wide > 0) {
	    WINSIZE_ROWS(win) = (unsigned short) *high;
	    WINSIZE_COLS(win) = (unsigned short) *wide;
	    (void) ioctl(fd, IOCTL_SET_WINSIZE, &win);
	}
    } else if (WINSIZE_ROWS(win) > 0 &&
	       WINSIZE_COLS(win) > 0) {
	*high = (short) WINSIZE_ROWS(win);
	*wide = (short) WINSIZE_COLS(win);
    }
}
#endif