]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - ncurses/tinfo/lib_setup.c
ncurses 6.4 - patch 20231007
[ncurses.git] / ncurses / tinfo / lib_setup.c
index a6527bfd096774b3f5b26f4a3267d6ce0c6e468b..b3cac8150347b852853b3e75f7260dd890a1e771 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * Copyright 2018-2019,2020 Thomas E. Dickey                                *
+ * Copyright 2018-2022,2023 Thomas E. Dickey                                *
  * Copyright 1998-2016,2017 Free Software Foundation, Inc.                  *
  *                                                                          *
  * Permission is hereby granted, free of charge, to any person obtaining a  *
@@ -49,7 +49,7 @@
 #include <locale.h>
 #endif
 
-MODULE_ID("$Id: lib_setup.c,v 1.207 2020/02/02 23:34:34 tom Exp $")
+MODULE_ID("$Id: lib_setup.c,v 1.228 2023/10/07 23:06:04 tom Exp $")
 
 /****************************************************************************
  *
@@ -66,7 +66,7 @@ MODULE_ID("$Id: lib_setup.c,v 1.207 2020/02/02 23:34:34 tom Exp $")
 #endif
 
 #if NEED_PTEM_H
- /* On SCO, they neglected to define struct winsize in termios.h -- it's only
+ /* On SCO, they neglected to define struct winsize in termios.h -- it is only
   * in termio.h and ptem.h (the former conflicts with other definitions).
   */
 # include <sys/stream.h>
@@ -272,6 +272,144 @@ use_tioctl(bool f)
 }
 #endif
 
+#if !(defined(USE_TERM_DRIVER) || defined(EXP_WIN32_DRIVER))
+static void
+_nc_default_screensize(TERMINAL *termp, int *linep, int *colp)
+{
+    /* if we can't get dynamic info about the size, use static */
+    if (*linep <= 0) {
+       *linep = (int) lines;
+    }
+    if (*colp <= 0) {
+       *colp = (int) columns;
+    }
+
+    /* the ultimate fallback, assume fixed 24x80 size */
+    if (*linep <= 0) {
+       *linep = 24;
+    }
+    if (*colp <= 0) {
+       *colp = 80;
+    }
+}
+
+static const char *
+skip_csi(const char *value)
+{
+    if (UChar(*value) == CSI_CHR) {
+       ++value;
+    } else if (*value == ESC_CHR && value[1] == L_BLOCK) {
+       value += 2;
+    }
+    return value;
+}
+
+static bool
+is_expected(const char *value, const char *expected)
+{
+    bool result = FALSE;
+    if (VALID_STRING(value)) {
+       const char *skipped = skip_csi(value);
+       if (skipped != value) {
+           if (!strcmp(skipped, expected))
+               result = TRUE;
+       }
+    }
+    return result;
+}
+
+static bool
+get_position(TERMINAL *termp, int fd, int *row, int *col)
+{
+    bool result = FALSE;
+    size_t need = strlen(user7);
+    int have;
+
+    have = (int) write(fd, user7, need);
+
+    if (have == (int) need) {
+       int y, x;
+       char buf[20];
+       char *s;
+       char ignore;
+
+       s = memset(buf, '\0', sizeof(buf));
+       do {
+           size_t ask = (sizeof(buf) - 1 - (size_t) (s - buf));
+           int got = (int) read(fd, s, ask);
+           if (got == 0)
+               break;
+           s += got;
+           *s = '\0';
+       } while (strchr(buf, 'R') == NULL && (size_t) (s + 1 - buf) < sizeof(buf));
+       T(("response %s", _nc_visbuf(buf)));
+       if (sscanf(skip_csi(buf), "%d;%d%c", &y, &x, &ignore) != 2
+           || (ignore != 'R' && ignore != ';')) {
+           *row = y;
+           *col = x;
+           result = TRUE;
+       }
+    }
+    T(("get_position %d,%d", *row, *col));
+    return result;
+}
+
+static bool
+set_position(TERMINAL *termp, int fd, int row, int col)
+{
+    bool result = FALSE;
+    char *actual = TIPARM_2(cursor_address, row, col);
+    T(("set_position %d,%d", row, col));
+    if (actual != NULL) {
+       size_t want = strlen(actual);
+       int have = (int) write(fd, actual, want);       /* FIXME - padding */
+       result = ((int) want == have);
+    }
+    return result;
+}
+
+/*
+ * This is a little more complicated than one might expect, because we do this
+ * before setting up the terminal modes, etc.
+ */
+static void
+_nc_check_screensize(TERMINAL *termp, int *linep, int *colp)
+{
+    int fd = fileno(stderr);
+    TTY saved;
+
+    if (NC_ISATTY(fd)
+       && VALID_STRING(cursor_address)
+       && is_expected(user7, "6n")
+       && is_expected(user6, "%i%d;%dR")
+       && GET_TTY(fd, &saved) == OK) {
+       int current_y, current_x;
+       int updated_y, updated_x;
+       TTY alter = saved;
+
+       alter.c_lflag &= (unsigned) ~(ECHO | ICANON | ISIG | IEXTEN);
+       alter.c_iflag &= (unsigned) ~(IXON | BRKINT | PARMRK);
+       alter.c_cc[VMIN] = 0;
+       alter.c_cc[VTIME] = 1;
+       SET_TTY(fd, &alter);
+
+       if (get_position(termp, fd, &current_y, &current_x)
+           && set_position(termp, fd, 9999, 9999)
+           && get_position(termp, fd, &updated_y, &updated_x)) {
+           *linep = updated_y;
+           *colp = updated_x;
+           set_position(termp, fd, current_y, current_x);
+       }
+       /* restore tty modes */
+       SET_TTY(fd, &saved);
+    }
+
+    _nc_default_screensize(termp, linep, colp);
+}
+#else
+#define _nc_check_screensize(termp, linep, colp) _nc_default_screensize(termp, linep, colp)
+#endif
+
 NCURSES_EXPORT(void)
 _nc_get_screensize(SCREEN *sp,
 #ifdef USE_TERM_DRIVER
@@ -305,11 +443,19 @@ _nc_get_screensize(SCREEN *sp,
     bool useEnv = _nc_prescreen.use_env;
     bool useTioctl = _nc_prescreen.use_tioctl;
 
+#ifdef EXP_WIN32_DRIVER
+    /* If we are here, then Windows console is used in terminfo mode.
+       We need to figure out the size using the console API
+     */
+    _nc_console_size(linep, colp);
+    T(("screen size: winconsole lines = %d columns = %d", *linep, *colp));
+#else
     /* figure out the size of the screen */
     T(("screen size: terminfo lines = %d columns = %d", lines, columns));
 
     *linep = (int) lines;
     *colp = (int) columns;
+#endif
 
 #if NCURSES_SP_FUNCS
     if (sp) {
@@ -381,22 +527,10 @@ _nc_get_screensize(SCREEN *sp,
                *colp = value;
                T(("screen size: environment COLUMNS = %d", *colp));
            }
-       }
-
-       /* if we can't get dynamic info about the size, use static */
-       if (*linep <= 0) {
-           *linep = (int) lines;
-       }
-       if (*colp <= 0) {
-           *colp = (int) columns;
-       }
 
-       /* the ultimate fallback, assume fixed 24x80 size */
-       if (*linep <= 0) {
-           *linep = 24;
-       }
-       if (*colp <= 0) {
-           *colp = 80;
+           _nc_default_screensize(termp, linep, colp);
+       } else {
+           _nc_check_screensize(termp, linep, colp);
        }
 
        /*
@@ -411,6 +545,8 @@ _nc_get_screensize(SCREEN *sp,
        OldNumber(termp, lines) = (short) (*linep);
        OldNumber(termp, columns) = (short) (*colp);
 #endif
+    } else {
+       _nc_check_screensize(termp, linep, colp);
     }
 
     T(("screen size is %dx%d", *linep, *colp));
@@ -495,6 +631,7 @@ _nc_setup_tinfo(const char *const tn, TERMTYPE2 *const tp)
      */
     if (status == TGETENT_YES) {
        unsigned n;
+       T(("_nc_setup_tinfo - resetting invalid booleans/strings"));
        for_each_boolean(n, tp) {
            if (!VALID_BOOLEAN(tp->Booleans[n]))
                tp->Booleans[n] = FALSE;
@@ -509,9 +646,9 @@ _nc_setup_tinfo(const char *const tn, TERMTYPE2 *const tp)
 #endif
 
 /*
-**     Take the real command character out of the CC environment variable
-**     and substitute it in for the prototype given in 'command_character'.
-*/
+ * Take the real command character out of the CC environment variable
+ * and substitute it in for the prototype given in 'command_character'.
+ */
 void
 _nc_tinfo_cmdch(TERMINAL *termp, int proto)
 {
@@ -527,9 +664,12 @@ _nc_tinfo_cmdch(TERMINAL *termp, int proto)
        char CC = *tmp;
 
        for_each_string(i, &(termp->type)) {
-           for (tmp = termp->type.Strings[i]; tmp && *tmp; tmp++) {
-               if (UChar(*tmp) == proto)
-                   *tmp = CC;
+           tmp = termp->type.Strings[i];
+           if (VALID_STRING(tmp)) {
+               for (; *tmp; ++tmp) {
+                   if (UChar(*tmp) == proto)
+                       *tmp = CC;
+               }
            }
        }
     }
@@ -566,7 +706,7 @@ NCURSES_EXPORT(int)
 _nc_unicode_locale(void)
 {
     int result = 0;
-#if defined(_WIN32) && USE_WIDEC_SUPPORT
+#if defined(_NC_WINDOWS) && USE_WIDEC_SUPPORT
     result = 1;
 #elif HAVE_LANGINFO_CODESET
     char *env = nl_langinfo(CODESET);
@@ -655,19 +795,25 @@ TINFO_SETUP_TERM(TERMINAL **tp,
 
     if (tname == 0) {
        tname = getenv("TERM");
-       if (tname == 0 || *tname == '\0') {
-#ifdef USE_TERM_DRIVER
+#if defined(EXP_WIN32_DRIVER)
+       if (!VALID_TERM_ENV(tname, NO_TERMINAL)) {
+           T(("Failure with TERM=%s", NonNull(tname)));
+           ret_error0(TGETENT_ERR, "TERM environment variable not set.\n");
+       }
+#elif defined(USE_TERM_DRIVER)
+       if (!NonEmpty(tname))
            tname = "unknown";
 #else
+       if (!NonEmpty(tname)) {
+           T(("Failure with TERM=%s", NonNull(tname)));
            ret_error0(TGETENT_ERR, "TERM environment variable not set.\n");
-#endif
        }
+#endif
     }
     myname = strdup(tname);
-
-    if (strlen(myname) > MAX_NAME_SIZE) {
+    if (myname == NULL || strlen(myname) > MAX_NAME_SIZE) {
        ret_error(TGETENT_ERR,
-                 "TERM environment must be <= %d characters.\n",
+                 "TERM environment must be 1..%d characters.\n",
                  MAX_NAME_SIZE,
                  free(myname));
     }
@@ -680,6 +826,10 @@ TINFO_SETUP_TERM(TERMINAL **tp,
      */
     if (Filedes == STDOUT_FILENO && !NC_ISATTY(Filedes))
        Filedes = STDERR_FILENO;
+#if defined(EXP_WIN32_DRIVER)
+    if (Filedes != STDERR_FILENO && NC_ISATTY(Filedes))
+       _setmode(Filedes, _O_BINARY);
+#endif
 
     /*
      * Check if we have already initialized to use this terminal.  If so, we
@@ -724,6 +874,7 @@ TINFO_SETUP_TERM(TERMINAL **tp,
                       "Not enough memory to create terminal structure.\n",
                       myname, free(myname));
        }
+       ++_nc_globals.terminal_count;
 #if HAVE_SYSCONF
        {
            long limit;
@@ -744,10 +895,14 @@ TINFO_SETUP_TERM(TERMINAL **tp,
 
 #ifdef USE_TERM_DRIVER
        INIT_TERM_DRIVER();
+       /*
+        * _nc_get_driver() will call td_CanHandle() for each driver, and win_driver
+        * needs file descriptor to do the test, so set it before calling.
+        */
+       termp->Filedes = (short) Filedes;
        TCB = (TERMINAL_CONTROL_BLOCK *) termp;
        code = _nc_globals.term_driver(TCB, myname, errret);
        if (code == OK) {
-           termp->Filedes = (short) Filedes;
            termp->_termname = strdup(myname);
        } else {
            ret_error1(errret ? *errret : TGETENT_ERR,
@@ -783,6 +938,7 @@ TINFO_SETUP_TERM(TERMINAL **tp,
                ret_error1(status, "unknown terminal type.\n",
                           myname, free(myname));
            } else {
+               free(myname);
                ret_error0(status, "unexpected return-code\n");
            }
        }
@@ -798,7 +954,7 @@ TINFO_SETUP_TERM(TERMINAL **tp,
 
        set_curterm(termp);
 
-       if (command_character)
+       if (VALID_STRING(command_character))
            _nc_tinfo_cmdch(termp, UChar(*command_character));
 
        /*
@@ -810,7 +966,7 @@ TINFO_SETUP_TERM(TERMINAL **tp,
        if (NC_ISATTY(Filedes)) {
            NCURSES_SP_NAME(def_shell_mode) (NCURSES_SP_ARG);
            NCURSES_SP_NAME(def_prog_mode) (NCURSES_SP_ARG);
-           baudrate();
+           NCURSES_SP_NAME(baudrate) (NCURSES_SP_ARG);
        }
        code = OK;
 #endif
@@ -887,6 +1043,7 @@ _nc_forget_prescr(void)
 {
     PRESCREEN_LIST *p, *q;
     pthread_t id = GetThreadID();
+    _nc_lock_global(screen);
     for (p = _nc_prescreen.allocated, q = 0; p != 0; q = p, p = p->next) {
        if (p->id == id) {
            if (q) {
@@ -898,6 +1055,7 @@ _nc_forget_prescr(void)
            break;
        }
     }
+    _nc_unlock_global(screen);
 }
 #endif /* USE_PTHREADS */
 
@@ -969,6 +1127,7 @@ _nc_setupterm(const char *tname,
     int rc = ERR;
     TERMINAL *termp = 0;
 
+    _nc_init_pthreads();
     _nc_lock_global(prescreen);
     START_TRACE();
     if (TINFO_SETUP_TERM(&termp, tname, Filedes, errret, reuse) == OK) {
@@ -978,6 +1137,7 @@ _nc_setupterm(const char *tname,
        }
     }
     _nc_unlock_global(prescreen);
+
     return rc;
 }
 #endif