--- fhandler.h.orig 2015-01-22 22:46:11.000000000 +0900 +++ fhandler.h 2015-02-25 18:21:13.836903000 +0900 @@ -1502,6 +1502,9 @@ class fhandler_pty_common: public fhandl copyto (fh); return fh; } + + protected: + BOOL process_opost_output (HANDLE h, const void *ptr, ssize_t& len, bool is_echo); }; class fhandler_pty_slave: public fhandler_pty_common @@ -1567,8 +1570,6 @@ class fhandler_pty_master: public fhandl DWORD dwProcessId; // Owner of master handles public: - int need_nl; // Next read should start with \n - /* Constructor */ fhandler_pty_master (int); --- tty.h.orig 2013-04-23 18:44:34.000000000 +0900 +++ tty.h 2015-02-26 19:41:46.121064500 +0900 @@ -67,7 +67,8 @@ public: * -ERRNO */ int ioctl_retval; - int write_error; + + int column; /* Current Column */ void setntty (_major_t t, _minor_t n) {ntty = (fh_devices) FHDEV (t, n);} dev_t getntty () const {return ntty;} --- fhandler_tty.cc.orig 2014-11-14 03:37:15.000000000 +0900 +++ fhandler_tty.cc 2015-02-25 18:51:59.908144200 +0900 @@ -145,10 +145,9 @@ fhandler_pty_common::__release_output_mu void fhandler_pty_master::doecho (const void *str, DWORD len) { - acquire_output_mutex (INFINITE); - if (!WriteFile (to_master, str, len, &len, NULL)) + ssize_t towrite = len; + if (!process_opost_output (to_master, str, towrite, true)) termios_printf ("Write to %p failed, %E", to_master); - release_output_mutex (); } int @@ -219,9 +218,8 @@ int fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on) { size_t rlen; - char outbuf[OUT_BUFFER_SIZE + 1]; + char outbuf[OUT_BUFFER_SIZE]; DWORD n; - int column = 0; int rc = 0; flush_to_slave (); @@ -229,34 +227,8 @@ fhandler_pty_master::process_slave_outpu if (len == 0) goto out; - if (need_nl) - { - /* We need to return a left over \n character, resulting from - \r\n conversion. Note that we already checked for FLUSHO and - output_stopped at the time that we read the character, so we - don't check again here. */ - if (buf) - buf[0] = '\n'; - need_nl = 0; - rc = 1; - goto out; - } - for (;;) { - /* Set RLEN to the number of bytes to read from the pipe. */ - rlen = len; - if (get_ttyp ()->ti.c_oflag & OPOST && get_ttyp ()->ti.c_oflag & ONLCR) - { - /* We are going to expand \n to \r\n, so don't read more than - half of the number of bytes requested. */ - rlen /= 2; - if (rlen == 0) - rlen = 1; - } - if (rlen > sizeof outbuf) - rlen = sizeof outbuf; - n = 0; for (;;) { @@ -265,7 +237,11 @@ fhandler_pty_master::process_slave_outpu if (n) break; if (hit_eof ()) - goto out; + { + set_errno (EIO); + rc = -1; + goto out; + } /* DISCARD (FLUSHO) and tcflush can finish here. */ if ((get_ttyp ()->ti.c_lflag & FLUSHO || !buf)) goto out; @@ -287,6 +263,26 @@ fhandler_pty_master::process_slave_outpu flush_to_slave (); } + /* Set RLEN to the number of bytes to read from the pipe. */ + rlen = len; + + char *optr; + optr = buf; + if (pktmode_on && buf) + { + *optr++ = TIOCPKT_DATA; + rlen -= 1; + } + + if (rlen == 0) + { + rc = optr - buf; + goto out; + } + + if (rlen > sizeof outbuf) + rlen = sizeof outbuf; + if (!ReadFile (get_handle (), outbuf, rlen, &n, NULL)) { termios_printf ("ReadFile failed, %E"); @@ -294,68 +290,12 @@ fhandler_pty_master::process_slave_outpu } termios_printf ("bytes read %u", n); - get_ttyp ()->write_error = 0; if (get_ttyp ()->ti.c_lflag & FLUSHO || !buf) continue; - char *optr; - optr = buf; - if (pktmode_on) - *optr++ = TIOCPKT_DATA; - - if (!(get_ttyp ()->ti.c_oflag & OPOST)) // post-process output - { - memcpy (optr, outbuf, n); - optr += n; - } - else // raw output mode - { - char *iptr = outbuf; - - while (n--) - { - switch (*iptr) - { - case '\r': - if ((get_ttyp ()->ti.c_oflag & ONOCR) && column == 0) - { - iptr++; - continue; - } - if (get_ttyp ()->ti.c_oflag & OCRNL) - *iptr = '\n'; - else - column = 0; - break; - case '\n': - if (get_ttyp ()->ti.c_oflag & ONLCR) - { - *optr++ = '\r'; - column = 0; - } - if (get_ttyp ()->ti.c_oflag & ONLRET) - column = 0; - break; - default: - column++; - break; - } - - /* Don't store data past the end of the user's buffer. This - can happen if the user requests a read of 1 byte when - doing \r\n expansion. */ - if (optr - buf >= (int) len) - { - if (*iptr != '\n' || n != 0) - system_printf ("internal error: %u unexpected characters", n); - need_nl = 1; - break; - } - - *optr++ = *iptr++; - } - } + memcpy (optr, outbuf, n); + optr += n; rc = optr - buf; break; @@ -633,7 +573,6 @@ fhandler_pty_slave::init (HANDLE h, DWOR ssize_t __stdcall fhandler_pty_slave::write (const void *ptr, size_t len) { - DWORD n; ssize_t towrite = len; bg_check_types bg = bg_check (SIGTTOU); @@ -644,46 +583,19 @@ fhandler_pty_slave::write (const void *p push_process_state process_state (PID_TTYOU); - while (len) + if (!process_opost_output (get_output_handle (), ptr, towrite, false)) { - n = MIN (OUT_BUFFER_SIZE, len); - char *buf = (char *)ptr; - ptr = (char *) ptr + n; - len -= n; - - while (tc ()->output_stopped) - cygwait (10); - acquire_output_mutex (INFINITE); - - /* Previous write may have set write_error to != 0. Check it here. - This is less than optimal, but the alternative slows down pty - writes enormously. */ - if (get_ttyp ()->write_error) - { - set_errno (get_ttyp ()->write_error); - towrite = -1; - get_ttyp ()->write_error = 0; - release_output_mutex (); - break; - } - - BOOL res = WriteFile (get_output_handle (), buf, n, &n, NULL); - release_output_mutex (); - if (!res) + DWORD err = GetLastError (); + termios_printf ("WriteFile failed, %E"); + switch (err) { - DWORD err = GetLastError (); - termios_printf ("WriteFile failed, %E"); - switch (err) - { - case ERROR_NO_DATA: - err = ERROR_IO_DEVICE; - default: - __seterrno_from_win_error (err); - } - raise (SIGHUP); /* FIXME: Should this be SIGTTOU? */ - towrite = -1; - break; + case ERROR_NO_DATA: + err = ERROR_IO_DEVICE; + default: + __seterrno_from_win_error (err); } + raise (SIGHUP); /* FIXME: Should this be SIGTTOU? */ + towrite = -1; } return towrite; } @@ -1227,7 +1139,7 @@ errout: fhandler_pty_master::fhandler_pty_master (int unit) : fhandler_pty_common (), pktmode (0), master_ctl (NULL), master_thread (NULL), from_master (NULL), to_master (NULL), - dwProcessId (0), need_nl (0) + dwProcessId (0) { if (unit >= 0) dev ().parse (DEV_PTYM_MAJOR, unit); @@ -1762,3 +1674,94 @@ fhandler_pty_master::fixup_after_exec () else from_master = to_master = NULL; } + +BOOL +fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& len, bool is_echo) +{ + ssize_t towrite = len; + BOOL res = TRUE; + while (towrite) + { + if (!is_echo) + { + if (tc ()->output_stopped && is_nonblocking ()) + { + if (towrite < len) + break; + else + { + set_errno(EAGAIN); + len = -1; + return TRUE; + } + } + while (tc ()->output_stopped) + cygwait (10); + } + + acquire_output_mutex (INFINITE); + + if (!(get_ttyp ()->ti.c_oflag & OPOST)) // raw output mode + { + DWORD n = MIN (OUT_BUFFER_SIZE, towrite); + res = WriteFile (h, ptr, n, &n, NULL); + if (!res) + break; + ptr = (char *) ptr + n; + towrite -= n; + } + else // post-process output + { + char outbuf[OUT_BUFFER_SIZE + 1]; + char *buf = (char *)ptr; + DWORD n = 0; + ssize_t rc = 0; + while (n < OUT_BUFFER_SIZE && rc < towrite) + { + switch (buf[rc]) + { + case '\r': + if ((get_ttyp ()->ti.c_oflag & ONOCR) && get_ttyp ()->column == 0) + { + rc ++; + continue; + } + if (get_ttyp ()->ti.c_oflag & OCRNL) + { + outbuf[n++] = '\n'; + rc ++; + } + else + { + outbuf[n++] = buf[rc++]; + get_ttyp ()->column = 0; + } + break; + case '\n': + if (get_ttyp ()->ti.c_oflag & ONLCR) + { + outbuf[n++] = '\r'; + get_ttyp ()->column = 0; + } + if (get_ttyp ()->ti.c_oflag & ONLRET) + get_ttyp ()->column = 0; + outbuf[n++] = buf[rc++]; + break; + default: + outbuf[n++] = buf[rc++]; + get_ttyp ()->column ++; + break; + } + } + res = WriteFile (h, outbuf, n, &n, NULL); + if (!res) + break; + ptr = (char *) ptr + rc; + towrite -= rc; + } + + release_output_mutex (); + } + len -= towrite; + return res; +} --- select.cc.orig 2014-10-11 21:14:29.000000000 +0900 +++ select.cc 2015-02-20 21:29:23.786421000 +0900 @@ -604,11 +604,6 @@ peek_pipe (select_record *s, bool from_s { fhandler_pty_master *fhm = (fhandler_pty_master *) fh; fhm->flush_to_slave (); - if (fhm->need_nl) - { - gotone = s->read_ready = true; - goto out; - } } break; default: --- tty.cc.orig 2013-10-19 05:07:35.000000000 +0900 +++ tty.cc 2015-02-21 14:46:01.045530400 +0900 @@ -237,6 +237,7 @@ tty::init () was_opened = false; master_pid = 0; is_console = false; + column = 0; } HANDLE