diff -r -wc bash-5.1/parse.y bash-5.1-work/parse.y *** bash-5.1/parse.y Sat Nov 28 18:10:06 2020 --- bash-5.1-work/parse.y Tue Jul 27 09:22:27 2021 *************** *** 37,42 **** --- 37,44 ---- #include #include "chartypes.h" #include + #include + #include #include "memalloc.h" *************** *** 1461,1466 **** --- 1463,1606 ---- char *current_readline_line = (char *)NULL; int current_readline_line_index = 0; + static void + freshline (void) + { + static int disabled = 0; + char buf [20]; + ssize_t n; + int r; + int flushing = 0; + struct termios tc, tc_orig; + fd_set readfds; + struct timeval tv, deadline, to; + + memset (buf, 0, sizeof(buf)); + + if (disabled) return; + + tcgetattr (0, &tc_orig); + tcgetattr (0, &tc); + cfmakeraw (&tc); + tcsetattr (0, TCSANOW, &tc); + + /* Probe, if there is input on our way, in which case we bail out. */ + FD_ZERO (&readfds); + FD_SET (0, &readfds); + tv.tv_sec = 0; + tv.tv_usec = 0; + r = select (1, &readfds, 0, 0, &tv); + if (r == 0) + { + /* Ok. how to get at the tty of readline? Writing to stdin seems + bogus. */ + char *query = "\033[6n"; + char *p = query; + ssize_t ntodo = strlen (query); + again: + n = write (0, p, 1); + if (n < 0 && (errno == EAGAIN || errno == EINTR)) + goto again; + if (n > 0) + { + ntodo -= n, p += n; + if (ntodo > 0) goto again; + } + + if (ntodo == 0) + { + suseconds_t m = 1000; + m *= 1000; + + p = buf; + /* + * We expect [{ROW};{COLUMN}R + * + * Read with a reasonable small timeout, but not too + * small, as this may be remote. select(2) at times is + * broken not updating tv, so use gettimeofday(2) to + * implement a dead line. + */ + flush: + to.tv_sec = 1; to.tv_usec = 0; + gettimeofday (&deadline, 0); + /* calcuate the dead line */ + deadline.tv_usec += to.tv_usec; + if (deadline.tv_usec > m) deadline.tv_sec++, deadline.tv_usec -= m; + deadline.tv_sec += to.tv_sec; + again2: + /* calcuate how long to wait */ + gettimeofday (&tv, 0); + + if (deadline.tv_usec < tv.tv_usec) + { + tv.tv_usec = deadline.tv_usec + m - tv.tv_usec; + tv.tv_sec++; + } + else + tv.tv_usec = deadline.tv_usec - tv.tv_usec; + + if (deadline.tv_sec < tv.tv_sec) + goto bailout; + else + tv.tv_sec = deadline.tv_sec - tv.tv_sec; + + FD_ZERO (&readfds); + FD_SET (0, &readfds); + r = select (1, &readfds, 0, 0, &tv); + if (r == 1 && FD_ISSET (0, &readfds)) + { + n = read (0, p, 1); + if (flushing) + goto again2; /* we're flushing */ + + if (n == 1) + { + if (*p == 'R') + goto seen; + if ((p == buf && *p != '\033') || + (p == buf+1 && *p != '[') || + ((p - buf + 2) > sizeof (buf))) + { + disabled = 1; + flushing = 1; + printf ("bash: Garbage seen\r\n"); + p = buf; + goto flush; + } + p++; + } + } + goto again2; + + seen: + *(++p) = 0; + { + int row, col; + if (2 == sscanf (buf, "\033[%d;%d", &row, &col)) + { + if (col != 1) write (0, "\r\n", 2); + } + else + goto bailout; + } + } + } + else + { + /* Input is on the way already. */ + } + goto fine; + + bailout: + printf ("bash: Something strange, disabling freshline.\r\n"); + disabled = 1; + fine: + tcsetattr (0, TCSANOW, &tc_orig); + } + static int yy_readline_get () { *************** *** 1485,1490 **** --- 1625,1631 ---- } sh_unset_nodelay_mode (fileno (rl_instream)); /* just in case */ + freshline (); current_readline_line = readline (current_readline_prompt ? current_readline_prompt : "");