]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - ncurses/tinfo/lib_setup.c
ncurses 6.5 - patch 20240519
[ncurses.git] / ncurses / tinfo / lib_setup.c
index f50c1cf16176028e511dcaaec21557fa7b5247ef..66226b1120dc54a043758825297fa9c8521c7935 100644 (file)
@@ -49,7 +49,7 @@
 #include <locale.h>
 #endif
 
-MODULE_ID("$Id: lib_setup.c,v 1.232 2024/03/02 19:42:13 tom Exp $")
+MODULE_ID("$Id: lib_setup.c,v 1.241 2024/05/11 19:07:34 tom Exp $")
 
 /****************************************************************************
  *
@@ -332,7 +332,9 @@ get_position(TERMINAL *termp, int fd, int *row, int *col)
        int y, x;
        char buf[20];
        char *s;
-       char ignore;
+       char cc;
+       const char *skipped;
+       int scanned;
 
        s = memset(buf, '\0', sizeof(buf));
        do {
@@ -343,51 +345,91 @@ get_position(TERMINAL *termp, int fd, int *row, int *col)
            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 != ';')) {
+       T(("CPR response %s", _nc_visbuf(buf)));
+       skipped = skip_csi(buf);
+       cc = '\0';
+       if (skipped != buf
+           && *skipped != '\0'
+           && (scanned = sscanf(skip_csi(buf), "%d;%d%c", &y, &x, &cc)) == 3
+           && (cc == 'R')) {
            *row = y;
            *col = x;
            result = TRUE;
        }
     }
-    T(("get_position %d,%d", *row, *col));
+    T(("get_position %s %d,%d", result ? "OK" : "ERR", *row, *col));
     return result;
 }
 
 static bool
-set_position(TERMINAL *termp, int fd, int row, int col)
+set_position(NCURSES_SP_DCLx TERMINAL *termp, int row, int col)
 {
-    bool result = FALSE;
+    bool result;
     char *actual = TIPARM_2(cursor_address, row, col);
-    T(("set_position %d,%d", row, col));
+    T((T_CALLED("set_position %d,%d)"), row, col));
+#if NCURSES_SP_FUNCS
+    result = (NCURSES_SP_NAME(_nc_putp) (NCURSES_SP_ARGx "set_position",
+                                        actual) == OK);
+    NCURSES_SP_NAME(_nc_flush) (NCURSES_SP_ARG);
+#else
+    /* This does not support padding because without sp-funcs, we have only
+     * the interface using stdio, but we are not guaranteed that Filedes
+     * is the same as fileno(stdout).
+     */
+    result = FALSE;
     if (actual != NULL) {
        size_t want = strlen(actual);
-       int have = (int) write(fd, actual, want);       /* FIXME - padding */
+       int have = (int) write(termp->Filedes, actual, want);
        result = ((int) want == have);
     }
-    return result;
+#endif
+    returnBool(result);
 }
 
 /*
  * This is a little more complicated than one might expect, because we do this
- * before setting up the terminal modes, etc.
+ * before setting up the terminal modes, etc., and cannot use the timeout or
+ * buffering functions.
+ *
+ * We check if the terminal description has the ECMA-48 CPR (cursor position
+ * report) in u7 and the response in u6.  The two variations of is_expected()
+ * cover the termcap style and terminfo style, and are equivalent as far as we
+ * are concerned.  For analyzing the response, we wait (a short time) for 'R'
+ * to be echoed, and then check if we received two integers in the response.
+ *
+ * In principle, this could run on "any" ECMA-48 terminal, but in practice,
+ * there is a scenario using GNU screen where it uses ncurses with a partially
+ * configured pseudo-terminal, and the CPR response goes to the wrong place.
+ * So we do a simple check to exclude pseudo-terminals.
  */
 static void
-_nc_check_screensize(TERMINAL *termp, int *linep, int *colp)
+_nc_check_screensize(SCREEN *sp, TERMINAL *termp, int *linep, int *colp)
 {
-    int fd = fileno(stderr);
+    int fd = termp->Filedes;
     TTY saved;
+    const char *name = NULL;
 
-    if (NC_ISATTY(fd)
+    if (IsRealTty(fd, name)
        && VALID_STRING(cursor_address)
        && is_expected(user7, "6n")
-       && is_expected(user6, "%i%d;%dR")
+       && (is_expected(user6, "%i%d;%dR") ||
+           is_expected(user6, "%i%p1%d;%p2%dR"))
        && GET_TTY(fd, &saved) == OK) {
        int current_y = -1, current_x = -1;
        int updated_y = -1, updated_x = -1;
        TTY alter = saved;
 
+#if NCURSES_SP_FUNCS
+       if (sp == NULL) {
+           sp = new_prescr();
+           sp->_term = termp;
+           NCURSES_SP_NAME(baudrate) (NCURSES_SP_ARG);
+       }
+#else
+       (void) sp;
+#endif
+
+       T(("trying CPR (u7/u6) with %s", name));
        alter.c_lflag &= (unsigned) ~(ECHO | ICANON | ISIG | IEXTEN);
        alter.c_iflag &= (unsigned) ~(IXON | BRKINT | PARMRK);
        alter.c_cc[VMIN] = 0;
@@ -395,20 +437,23 @@ _nc_check_screensize(TERMINAL *termp, int *linep, int *colp)
        SET_TTY(fd, &alter);
 
        if (get_position(termp, fd, &current_y, &current_x)
-           && set_position(termp, fd, 9999, 9999)
+           && set_position(NCURSES_SP_ARGx termp, 9999, 9999)
            && get_position(termp, fd, &updated_y, &updated_x)) {
            *linep = updated_y;
            *colp = updated_x;
-           set_position(termp, fd, current_y, current_x);
+           set_position(NCURSES_SP_ARGx termp, current_y, current_x);
        }
        /* restore tty modes */
        SET_TTY(fd, &saved);
+    } else {
+       T(("NOT trying CPR with fd %d (%s): %s",
+          fd, NonNull(name), NC_ISATTY(fd) ? "tty" : "not a tty"));
     }
 
     _nc_default_screensize(termp, linep, colp);
 }
 #else /* !USE_CHECK_SIZE */
-#define _nc_check_screensize(termp, linep, colp)       /* nothing */
+#define _nc_check_screensize(sp, termp, linep, colp)   /* nothing */
 #endif
 #endif /* !(defined(USE_TERM_DRIVER) || defined(EXP_WIN32_DRIVER)) */
 
@@ -445,6 +490,7 @@ _nc_get_screensize(SCREEN *sp,
     bool useEnv = _nc_prescreen.use_env;
     bool useTioctl = _nc_prescreen.use_tioctl;
 
+    T((T_CALLED("_nc_get_screensize (%p)"), (void *) sp));
 #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
@@ -466,6 +512,7 @@ _nc_get_screensize(SCREEN *sp,
     }
 #endif
 
+    T(("useEnv:%d useTioctl:%d", useEnv, useTioctl));
     if (useEnv || useTioctl) {
 #ifdef __EMX__
        {
@@ -522,17 +569,17 @@ _nc_get_screensize(SCREEN *sp,
             * variable.
             */
            if ((value = _nc_getenv_num("LINES")) > 0) {
-               *linep = value;
+               *linep = Min(value, MAX_ENV_LINES);
                T(("screen size: environment LINES = %d", *linep));
            }
            if ((value = _nc_getenv_num("COLUMNS")) > 0) {
-               *colp = value;
+               *colp = Min(value, MAX_ENV_COLUMNS);
                T(("screen size: environment COLUMNS = %d", *colp));
            }
 
            _nc_default_screensize(termp, linep, colp);
        } else {
-           _nc_check_screensize(termp, linep, colp);
+           _nc_check_screensize(sp, termp, linep, colp);
        }
 
        /*
@@ -548,7 +595,7 @@ _nc_get_screensize(SCREEN *sp,
        OldNumber(termp, columns) = (short) (*colp);
 #endif
     } else {
-       _nc_check_screensize(termp, linep, colp);
+       _nc_check_screensize(sp, termp, linep, colp);
     }
 
     T(("screen size is %dx%d", *linep, *colp));
@@ -565,6 +612,7 @@ _nc_get_screensize(SCREEN *sp,
     TABSIZE = my_tabsize;
 #endif
     T(("TABSIZE = %d", TABSIZE));
+    returnVoid;
 #endif /* USE_TERM_DRIVER */
 }