aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/fhandler.h1
-rw-r--r--winsup/cygwin/fhandler_tty.cc234
-rw-r--r--winsup/cygwin/spawn.cc18
-rw-r--r--winsup/cygwin/tty.cc3
-rw-r--r--winsup/cygwin/tty.h3
5 files changed, 229 insertions, 30 deletions
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 9fd95c0..b4ba942 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2332,6 +2332,7 @@ class fhandler_pty_slave: public fhandler_pty_common
}
bool setup_pseudoconsole (STARTUPINFOEXW *si, bool nopcon);
void close_pseudoconsole (void);
+ bool term_has_pcon_cap (const WCHAR *env);
void set_switch_to_pcon (void);
void reset_switch_to_pcon (void);
void mask_switch_to_pcon_in (bool mask);
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 0865c1f..e4e94f1 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -1631,33 +1631,27 @@ fhandler_pty_master::write (const void *ptr, size_t len)
static char wpbuf[wpbuf_len];
static int ixput = 0;
- if (ixput == 0 && buf[0] != '\033')
- { /* fail-safe */
- WriteFile (to_slave, "\033[1;1R", 6, &wLen, NULL); /* dummy */
- get_ttyp ()->pcon_start = false;
+ if (ixput + nlen < wpbuf_len)
+ {
+ memcpy (wpbuf + ixput, buf, nlen);
+ ixput += nlen;
}
else
{
- if (ixput + nlen < wpbuf_len)
- for (size_t i=0; i<nlen; i++)
- wpbuf[ixput++] = buf[i];
- else
- {
- WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
- ixput = 0;
- get_ttyp ()->pcon_start = false;
- WriteFile (to_slave, buf, nlen, &wLen, NULL);
- }
- if (ixput && memchr (wpbuf, 'R', ixput))
- {
- WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
- ixput = 0;
- get_ttyp ()->pcon_start = false;
- }
- ReleaseMutex (input_mutex);
- mb_str_free (buf);
- return len;
+ WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+ ixput = 0;
+ get_ttyp ()->pcon_start = false;
+ WriteFile (to_slave, buf, nlen, &wLen, NULL);
}
+ if (ixput && memchr (wpbuf, 'R', ixput))
+ {
+ WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+ ixput = 0;
+ get_ttyp ()->pcon_start = false;
+ }
+ ReleaseMutex (input_mutex);
+ mb_str_free (buf);
+ return len;
}
WriteFile (to_slave, buf, nlen, &wLen, NULL);
@@ -2169,6 +2163,22 @@ fhandler_pty_master::pty_master_fwd_thread ()
char *ptr = outbuf;
if (get_ttyp ()->h_pseudo_console)
{
+ if (!get_ttyp ()->has_set_title)
+ {
+ /* Remove Set title sequence */
+ char *p0, *p1;
+ p0 = outbuf;
+ while ((p0 = (char *) memmem (p0, rlen, "\033]0;", 4)))
+ {
+ p1 = (char *) memchr (p0, '\007', rlen - (p0 - outbuf));
+ if (p1)
+ {
+ memmove (p0, p1 + 1, rlen - (p1 + 1 - outbuf));
+ rlen -= p1 + 1 - p0;
+ wlen = rlen;
+ }
+ }
+ }
/* Remove CSI > Pm m */
int state = 0;
int start_at = 0;
@@ -2659,3 +2669,181 @@ fhandler_pty_slave::close_pseudoconsole (void)
get_ttyp ()->pcon_start = false;
}
}
+
+static bool
+has_ansi_escape_sequences (const WCHAR *env)
+{
+ /* Retrieve TERM name */
+ const char *term = NULL;
+ char term_str[260];
+ if (env)
+ {
+ for (const WCHAR *p = env; *p != L'\0'; p += wcslen (p) + 1)
+ if (swscanf (p, L"TERM=%236s", term_str) == 1)
+ {
+ term = term_str;
+ break;
+ }
+ }
+ else
+ term = getenv ("TERM");
+
+ if (!term)
+ return false;
+
+ /* If cursor_home is not "\033[H", terminal is not supposed to
+ support ANSI escape sequences. */
+ char tinfo[260];
+ __small_sprintf (tinfo, "/usr/share/terminfo/%02x/%s", term[0], term);
+ path_conv path (tinfo);
+ WCHAR wtinfo[260];
+ path.get_wide_win32_path (wtinfo);
+ HANDLE h;
+ h = CreateFileW (wtinfo, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, 0, NULL);
+ if (h == NULL)
+ return false;
+ char terminfo[4096];
+ DWORD n;
+ ReadFile (h, terminfo, sizeof (terminfo), &n, 0);
+ CloseHandle (h);
+
+ int num_size = 2;
+ if (*(int16_t *)terminfo == 01036 /* MAGIC2 */)
+ num_size = 4;
+ const int name_pos = 12; /* Position of terminal name */
+ const int name_size = *(int16_t *) (terminfo + 2);
+ const int bool_count = *(int16_t *) (terminfo + 4);
+ const int num_count = *(int16_t *) (terminfo + 6);
+ const int str_count = *(int16_t *) (terminfo + 8);
+ const int str_size = *(int16_t *) (terminfo + 10);
+ const int cursor_home = 12; /* cursor_home entry index */
+ if (cursor_home >= str_count)
+ return false;
+ int str_idx_pos = name_pos + name_size + bool_count + num_size * num_count;
+ if (str_idx_pos & 1)
+ str_idx_pos ++;
+ const int16_t *str_idx = (int16_t *) (terminfo + str_idx_pos);
+ const char *str_table = (const char *) (str_idx + str_count);
+ if (str_idx + cursor_home >= (int16_t *) (terminfo + n))
+ return false;
+ if (str_idx[cursor_home] == -1)
+ return false;
+ const char *cursor_home_str = str_table + str_idx[cursor_home];
+ if (cursor_home_str >= str_table + str_size)
+ return false;
+ if (cursor_home_str >= terminfo + n)
+ return false;
+ if (strcmp (cursor_home_str, "\033[H") != 0)
+ return false;
+ return true;
+}
+
+bool
+fhandler_pty_slave::term_has_pcon_cap (const WCHAR *env)
+{
+ if (get_ttyp ()->pcon_cap_checked)
+ return get_ttyp ()->has_csi6n;
+
+ DWORD n;
+ char buf[1024];
+ char *p;
+ int len;
+ int x1, y1, x2, y2;
+ tcflag_t c_lflag;
+ DWORD t0;
+
+ /* Check if terminal has ANSI escape sequence. */
+ if (!has_ansi_escape_sequences (env))
+ goto maybe_dumb;
+
+ /* Check if terminal has CSI6n */
+ WaitForSingleObject (input_mutex, INFINITE);
+ c_lflag = get_ttyp ()->ti.c_lflag;
+ get_ttyp ()->ti.c_lflag &= ~ICANON;
+ /* Set h_pseudo_console and pcon_start so that the response
+ will sent to io_handle rather than io_handle_cyg. */
+ get_ttyp ()->h_pseudo_console = (HPCON *) -1; /* dummy */
+ /* pcon_start will be cleared in master write() when CSI6n is responded. */
+ get_ttyp ()->pcon_start = true;
+ WriteFile (get_output_handle_cyg (), "\033[6n", 4, &n, NULL);
+ ReleaseMutex (input_mutex);
+ p = buf;
+ len = sizeof (buf) - 1;
+ t0 = GetTickCount ();
+ do
+ {
+ if (::bytes_available (n, get_handle ()) && n)
+ {
+ ReadFile (get_handle (), p, len, &n, NULL);
+ p += n;
+ len -= n;
+ *p = '\0';
+ char *p1 = strrchr (buf, '\033');
+ if (p1 == NULL || sscanf (p1, "\033[%d;%dR", &y1, &x1) != 2)
+ continue;
+ break;
+ }
+ else if (GetTickCount () - t0 > 40) /* Timeout */
+ goto not_has_csi6n;
+ else
+ Sleep (1);
+ }
+ while (len);
+ if (len == 0)
+ goto not_has_csi6n;
+
+ get_ttyp ()->has_csi6n = true;
+ get_ttyp ()->pcon_cap_checked = true;
+
+ /* Check if terminal has set-title capability */
+ WaitForSingleObject (input_mutex, INFINITE);
+ /* Set pcon_start again because it should be cleared
+ in master write(). */
+ get_ttyp ()->pcon_start = true;
+ WriteFile (get_output_handle_cyg (), "\033]0;\033\\\033[6n", 10, &n, NULL);
+ ReleaseMutex (input_mutex);
+ p = buf;
+ len = sizeof (buf) - 1;
+ do
+ {
+ ReadFile (get_handle (), p, len, &n, NULL);
+ p += n;
+ len -= n;
+ *p = '\0';
+ char *p2 = strrchr (buf, '\033');
+ if (p2 == NULL || sscanf (p2, "\033[%d;%dR", &y2, &x2) != 2)
+ continue;
+ break;
+ }
+ while (len);
+ WaitForSingleObject (input_mutex, INFINITE);
+ get_ttyp ()->h_pseudo_console = NULL;
+ get_ttyp ()->ti.c_lflag = c_lflag;
+ ReleaseMutex (input_mutex);
+
+ if (len == 0)
+ return true;
+
+ if (x2 == x1 && y2 == y1)
+ /* If "\033]0;\033\\" does not move cursor position,
+ set-title is supposed to be supported. */
+ get_ttyp ()->has_set_title = true;
+ else
+ /* Try to erase garbage string caused by "\033]0;\033\\" */
+ for (int i=0; i<x2-x1; i++)
+ WriteFile (get_output_handle_cyg (), "\b \b", 3, &n, NULL);
+ return true;
+
+not_has_csi6n:
+ WaitForSingleObject (input_mutex, INFINITE);
+ /* If CSI6n is not responded, pcon_start is not cleared
+ in master write(). Therefore, clear it here manually. */
+ get_ttyp ()->pcon_start = false;
+ get_ttyp ()->h_pseudo_console = NULL;
+ get_ttyp ()->ti.c_lflag = c_lflag;
+ ReleaseMutex (input_mutex);
+maybe_dumb:
+ get_ttyp ()->pcon_cap_checked = true;
+ return false;
+}
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index a2f7697..92d190d 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -647,13 +647,17 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
ZeroMemory (&si_pcon, sizeof (si_pcon));
STARTUPINFOW *si_tmp = &si;
if (!iscygwin () && ptys_primary && is_console_app (runpath))
- if (ptys_primary->setup_pseudoconsole (&si_pcon,
- mode != _P_OVERLAY && mode != _P_WAIT))
- {
- c_flags |= EXTENDED_STARTUPINFO_PRESENT;
- si_tmp = &si_pcon.StartupInfo;
- enable_pcon = true;
- }
+ {
+ bool nopcon = mode != _P_OVERLAY && mode != _P_WAIT;
+ if (!ptys_primary->term_has_pcon_cap (envblock))
+ nopcon = true;
+ if (ptys_primary->setup_pseudoconsole (&si_pcon, nopcon))
+ {
+ c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+ si_tmp = &si_pcon.StartupInfo;
+ enable_pcon = true;
+ }
+ }
loop:
/* When ruid != euid we create the new process under the current original
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index d60f275..7e3b88b 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -242,6 +242,9 @@ tty::init ()
term_code_page = 0;
pcon_last_time = 0;
pcon_start = false;
+ pcon_cap_checked = false;
+ has_csi6n = false;
+ has_set_title = false;
}
HANDLE
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index c491d38..4e9199d 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -101,6 +101,9 @@ private:
UINT term_code_page;
DWORD pcon_last_time;
HANDLE h_pcon_write_pipe;
+ bool pcon_cap_checked;
+ bool has_csi6n;
+ bool has_set_title;
public:
HANDLE from_master () const { return _from_master; }