]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - progs/reset_cmd.c
ncurses 6.4 - patch 20240420
[ncurses.git] / progs / reset_cmd.c
index 94ad75089e436feb4b149d14f0ba6657cb2d0c0b..6ae3b673e340037d94baf6d4a4e9c924f320e445 100644 (file)
@@ -1,5 +1,6 @@
 /****************************************************************************
- * Copyright (c) 2016 Free Software Foundation, Inc.                        *
+ * Copyright 2019-2023,2024 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            *
@@ -31,6 +32,7 @@
  ****************************************************************************/
 
 #include <reset_cmd.h>
+#include <tty_settings.h>
 
 #include <errno.h>
 #include <stdio.h>
 #endif
 
 #if NEED_PTEM_H
-/* they neglected to define struct winsize in termios.h -- it's only
+/* 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.5 2016/08/06 21:04:54 tom Exp $")
+MODULE_ID("$Id: reset_cmd.c,v 1.37 2024/04/08 17:29:34 tom Exp $")
 
 /*
  * SCO defines TIOCGSIZE and the corresponding struct.  Other systems (SunOS,
@@ -73,47 +75,27 @@ MODULE_ID("$Id: reset_cmd.c,v 1.5 2016/08/06 21:04:54 tom Exp $")
 # endif
 #endif
 
-static int my_fd;
+#define set_flags(target, mask)    target |= mask
+#define clear_flags(target, mask)  target &= ~((unsigned)(mask))
+
 static FILE *my_file;
-static TTY original_settings;
 
-static bool can_restore = FALSE;
 static bool use_reset = FALSE; /* invoked as reset */
 static bool use_init = FALSE;  /* invoked as init */
 
-static void
-exit_error(void)
+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(EXIT_FAILURE);
-    /* NOTREACHED */
-}
-
-static void
-failed(const char *msg)
-{
-    char temp[BUFSIZ];
-
-    _nc_STRCPY(temp, _nc_progname, sizeof(temp));
-    _nc_STRCAT(temp, ": ", sizeof(temp));
-    perror(strncat(temp, msg, sizeof(temp) - strlen(temp) - 2));
-    exit_error();
+    ExitProgram(ErrSystem(code));
     /* NOTREACHED */
 }
 
-static bool
-get_tty_settings(int fd, TTY * tty_settings)
-{
-    bool success = TRUE;
-    my_fd = fd;
-    if (fd < 0 || GET_TTY(my_fd, tty_settings) < 0) {
-       success = FALSE;
-    }
-    return success;
-}
-
 static bool
 cat_file(char *file)
 {
@@ -123,7 +105,7 @@ cat_file(char *file)
     bool sent = FALSE;
 
     if (file != 0) {
-       if ((fp = fopen(file, "r")) == 0)
+       if ((fp = safe_fopen(file, "r")) == 0)
            failed(file);
 
        while ((nr = fread(buf, sizeof(char), sizeof(buf), fp)) != 0) {
@@ -209,25 +191,102 @@ out_char(int c)
 #define reset_char(item, value) \
     tty_settings->c_cc[item] = CHK(tty_settings->c_cc[item], value)
 
+/*
+ * Simplify ifdefs
+ */
+#ifndef BSDLY
+#define BSDLY 0
+#endif
+#ifndef CRDLY
+#define CRDLY 0
+#endif
+#ifndef ECHOCTL
+#define ECHOCTL 0
+#endif
+#ifndef ECHOKE
+#define ECHOKE 0
+#endif
+#ifndef ECHOPRT
+#define ECHOPRT 0
+#endif
+#ifndef FFDLY
+#define FFDLY 0
+#endif
+#ifndef IMAXBEL
+#define IMAXBEL 0
+#endif
+#ifndef IUCLC
+#define IUCLC 0
+#endif
+#ifndef IXANY
+#define IXANY 0
+#endif
+#ifndef NLDLY
+#define NLDLY 0
+#endif
+#ifndef OCRNL
+#define OCRNL 0
+#endif
+#ifndef OFDEL
+#define OFDEL 0
+#endif
+#ifndef OFILL
+#define OFILL 0
+#endif
+#ifndef OLCUC
+#define OLCUC 0
+#endif
+#ifndef ONLCR
+#define ONLCR 0
+#endif
+#ifndef ONLRET
+#define ONLRET 0
+#endif
+#ifndef ONOCR
+#define ONOCR 0
+#endif
+#ifndef OXTABS
+#define OXTABS 0
+#endif
+#ifndef TAB3
+#define TAB3 0
+#endif
+#ifndef TABDLY
+#define TABDLY 0
+#endif
+#ifndef TOSTOP
+#define TOSTOP 0
+#endif
+#ifndef VTDLY
+#define VTDLY 0
+#endif
+#ifndef XCASE
+#define XCASE 0
+#endif
+
 /*
  * Reset the terminal mode bits to a sensible state.  Very useful after
  * a child program dies in raw mode.
  */
 void
-reset_tty_settings(TTY * tty_settings)
+reset_tty_settings(int fd, TTY * tty_settings, int noset)
 {
-#ifdef TERMIOS
-    tcgetattr(my_fd, tty_settings);
-#else
-    stty(my_fd, tty_settings);
+    unsigned mask;
+#ifdef TIOCMGET
+    int modem_bits;
 #endif
 
+    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
@@ -253,108 +312,69 @@ reset_tty_settings(TTY * tty_settings)
     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
-
-    SET_TTY(my_fd, tty_settings);
+    clear_flags(tty_settings->c_iflag, (IGNBRK
+                                       | PARMRK
+                                       | INPCK
+                                       | ISTRIP
+                                       | INLCR
+                                       | IGNCR
+                                       | IUCLC
+                                       | IXANY
+                                       | IXOFF));
+
+    set_flags(tty_settings->c_iflag, (BRKINT
+                                     | IGNPAR
+                                     | ICRNL
+                                     | IXON
+                                     | IMAXBEL));
+
+    clear_flags(tty_settings->c_oflag, (0
+                                       | OLCUC
+                                       | OCRNL
+                                       | ONOCR
+                                       | ONLRET
+                                       | OFILL
+                                       | OFDEL
+                                       | NLDLY
+                                       | CRDLY
+                                       | TABDLY
+                                       | BSDLY
+                                       | VTDLY
+                                       | FFDLY));
+
+    set_flags(tty_settings->c_oflag, (OPOST
+                                     | ONLCR));
+
+    mask = (CSIZE | CSTOPB | PARENB | PARODD);
+#ifdef TIOCMGET
+    /* leave clocal alone if this appears to use a modem */
+    if (ioctl(fd, TIOCMGET, &modem_bits) == -1)
+       mask |= CLOCAL;
+#else
+    /* cannot check - use the behavior from tset */
+    mask |= CLOCAL;
+#endif
+    clear_flags(tty_settings->c_cflag, mask);
+
+    set_flags(tty_settings->c_cflag, (CS8 | CREAD));
+    clear_flags(tty_settings->c_lflag, (ECHONL
+                                       | NOFLSH
+                                       | TOSTOP
+                                       | ECHOPRT
+                                       | XCASE));
+
+    set_flags(tty_settings->c_lflag, (ISIG
+                                     | ICANON
+                                     | ECHO
+                                     | ECHOE
+                                     | ECHOK
+                                     | ECHOCTL
+                                     | ECHOKE));
+#endif /* TERMIOS */
+
+    if (!noset) {
+       SET_TTY(fd, tty_settings);
+    }
 }
 
 /*
@@ -367,7 +387,7 @@ default_erase(void)
     int result;
 
     if (over_strike
-       && key_backspace != 0
+       && VALID_STRING(key_backspace)
        && strlen(key_backspace) == 1) {
        result = key_backspace[0];
     } else {
@@ -388,6 +408,13 @@ default_erase(void)
 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
@@ -405,6 +432,7 @@ set_control_chars(TTY * tty_settings, int my_erase, int my_intr, int my_kill)
                                          ? my_kill
                                          : CKILL);
     }
+#endif
 }
 
 /*
@@ -414,29 +442,49 @@ set_control_chars(TTY * tty_settings, int my_erase, int my_intr, int my_kill)
 void
 set_conversions(TTY * tty_settings)
 {
-#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 */
+#if defined(EXP_WIN32_DRIVER)
+    /* FIXME */
+#else
+    set_flags(tty_settings->c_oflag, ONLCR);
+    set_flags(tty_settings->c_iflag, ICRNL);
+    set_flags(tty_settings->c_lflag, ECHO);
+    set_flags(tty_settings->c_oflag, OXTABS);
 
     /* test used to be tgetflag("NL") */
-    if (newline != (char *) 0 && newline[0] == '\n' && !newline[1]) {
+    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);
+       clear_flags(tty_settings->c_oflag, ONLCR);
+       clear_flags(tty_settings->c_iflag, ICRNL);
     }
-#ifdef OXTABS
+#if OXTABS
     /* test used to be tgetflag("pt") */
-    if (has_hardware_tabs)     /* Print tabs. */
-       tty_settings->c_oflag &= ~OXTABS;
+    if (VALID_STRING(set_tab) && VALID_STRING(clear_all_tabs))
+       clear_flags(tty_settings->c_oflag, OXTABS);
 #endif /* OXTABS */
-    tty_settings->c_lflag |= (ECHOE | ECHOK);
+    set_flags(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;
 }
 
 /*
@@ -449,57 +497,45 @@ set_conversions(TTY * tty_settings)
 static bool
 reset_tabstops(int wide)
 {
-    if ((init_tabs != 8) && (set_tab && clear_all_tabs)) {
+    if ((init_tabs != 8)
+       && VALID_NUMERIC(init_tabs)
+       && VALID_STRING(set_tab)
+       && VALID_STRING(clear_all_tabs)) {
        int c;
 
-       (void) putc('\r', my_file);     /* Force to left margin. */
+       to_left_margin();
        tputs(clear_all_tabs, 0, out_char);
-
-       for (c = 8; c < wide; c += 8) {
-           /* Get to the right column.  In BSD tset, this used to try a bunch
-            * of half-clever things with cup and hpa, for an average saving of
-            * somewhat less than two character times per tab stop, less than
-            * .01 sec at 2400cps.  We lost all this cruft because it seemed to
-            * be introducing some odd bugs.
-            * -----------12345678----------- */
-           (void) fputs("        ", my_file);
-           tputs(set_tab, 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();
        }
-       putc('\r', my_file);
        return (TRUE);
     }
     return (FALSE);
 }
 
-static bool
-sent_string(const char *s)
-{
-    bool sent = FALSE;
-    if (s != 0) {
-       tputs(s, 0, out_char);
-       sent = TRUE;
-    }
-    return sent;
-}
-
-#define PUTCHAR(c) fputc(c, my_file)
-
 /* Output startup string. */
 bool
-send_init_strings(TTY * old_settings)
+send_init_strings(int fd GCC_UNUSED, TTY * old_settings)
 {
     int i;
     bool need_flush = FALSE;
 
-#ifdef TAB3
+    (void) old_settings;
+#if TAB3
     if (old_settings != 0 &&
        old_settings->c_oflag & (TAB3 | ONLCR | OCRNL | ONLRET)) {
        old_settings->c_oflag &= (TAB3 | ONLCR | OCRNL | ONLRET);
-       SET_TTY(my_fd, old_settings);
+       SET_TTY(fd, old_settings);
     }
 #endif
     if (use_reset || use_init) {
-       if (init_prog != 0) {
+       if (VALID_STRING(init_prog)) {
            IGNORE_RC(system(init_prog));
        }
 
@@ -511,38 +547,37 @@ send_init_strings(TTY * old_settings)
                                  ? reset_2string
                                  : init_2string);
 
-       if (set_lr_margin != 0) {
-           need_flush |= sent_string(TPARM_2(set_lr_margin, 0,
-                                             columns - 1));
-       } else if (set_left_margin_parm != 0
-                  && set_right_margin_parm != 0) {
-           need_flush |= sent_string(TPARM_1(set_left_margin_parm, 0));
-           need_flush |= sent_string(TPARM_1(set_right_margin_parm,
-                                             columns - 1));
-       } else if (clear_margins != 0
-                  && set_left_margin != 0
-                  && set_right_margin != 0) {
+       if (VALID_STRING(clear_margins)) {
            need_flush |= sent_string(clear_margins);
-           if (carriage_return != 0) {
-               need_flush |= sent_string(carriage_return);
-           } else {
-               PUTCHAR('\r');
-           }
+       }
+#if defined(set_lr_margin)
+       else if (VALID_STRING(set_lr_margin)) {
+           need_flush |= sent_string(TIPARM_2(set_lr_margin, 0, columns - 1));
+       }
+#endif
+#if defined(set_left_margin_parm) && defined(set_right_margin_parm)
+       else 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));
+       }
+#endif
+       else if (VALID_STRING(set_left_margin)
+                && VALID_STRING(set_right_margin)) {
+           need_flush |= to_left_margin();
            need_flush |= sent_string(set_left_margin);
-           if (parm_right_cursor) {
-               need_flush |= sent_string(TPARM_1(parm_right_cursor,
-                                                 columns - 1));
+           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++) {
-                   PUTCHAR(' ');
+                   out_char(' ');
+                   need_flush = TRUE;
                }
            }
            need_flush |= sent_string(set_right_margin);
-           if (carriage_return != 0) {
-               need_flush |= sent_string(carriage_return);
-           } else {
-               PUTCHAR('\r');
-           }
+           need_flush |= to_left_margin();
        }
 
        need_flush |= reset_tabstops(columns);
@@ -567,15 +602,23 @@ show_tty_change(TTY * old_settings,
                int which,
                unsigned def)
 {
-    unsigned older, newer;
+    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)) {
@@ -619,58 +662,36 @@ reset_flush(void)
 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
 /*
- * Open a file descriptor on the current terminal, to obtain its settings.
- * stderr is less likely to be redirected than stdout; try that first.
+ * Set window size if not set already, but update our copy of the values if the
+ * size was set.
  */
-int
-save_tty_settings(TTY * tty_settings)
-{
-    if (!get_tty_settings(STDERR_FILENO, tty_settings) &&
-       !get_tty_settings(STDOUT_FILENO, tty_settings) &&
-       !get_tty_settings(STDIN_FILENO, tty_settings) &&
-       !get_tty_settings(open("/dev/tty", O_RDWR), tty_settings)) {
-       failed("terminal attributes");
-    }
-    can_restore = TRUE;
-    original_settings = *tty_settings;
-    return my_fd;
-}
-
 void
-restore_tty_settings(void)
-{
-    if (can_restore)
-       SET_TTY(my_fd, &original_settings);
-}
-
-/* Set the modes if they've changed. */
-void
-update_tty_settings(TTY * old_settings, TTY * new_settings)
-{
-    if (memcmp(new_settings, old_settings, sizeof(TTY))) {
-       SET_TTY(my_fd, new_settings);
-    }
-}
-
-#if HAVE_SIZECHANGE
-/* Set window size if not set already */
-void
-set_window_size(int fd, int high, int wide)
+set_window_size(int fd, NCURSES_INT2 *high, NCURSES_INT2 *wide)
 {
     STRUCT_WINSIZE win;
     (void) ioctl(fd, IOCTL_GET_WINSIZE, &win);
     if (WINSIZE_ROWS(win) == 0 &&
-       WINSIZE_COLS(win) == 0 &&
-       high > 0 && wide > 0) {
-       WINSIZE_ROWS(win) = (unsigned short) high;
-       WINSIZE_COLS(win) = (unsigned short) wide;
-       (void) ioctl(fd, IOCTL_SET_WINSIZE, &win);
+       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