static int read_up_to(int n) { assert(n > 0); const int prevlen = input_buffer.len; bytebuffer_resize(&input_buffer, prevlen + n); int read_n = 0; while (read_n <= n) { ssize_t r = 0; if (read_n < n) { r = read(inout, input_buffer.buf + prevlen + read_n, n - read_n); } #ifdef __CYGWIN__ // While linux man for tty says when VMIN == 0 && VTIME == 0, read // should return 0 when there is nothing to read, cygwin's read returns // -1. Not sure why and if it's correct to ignore it, but let's pretend // it's zero. if (r < 0) r = 0; #endif if (r < 0) { // EAGAIN / EWOULDBLOCK shouldn't occur here assert(errno != EAGAIN && errno != EWOULDBLOCK); return -1; } else if (r > 0) { read_n += r; } else { bytebuffer_resize(&input_buffer, prevlen + read_n); return read_n; } } assert(!"unreachable"); return 0; }
static int wait_fill_event(struct tb_event *event, struct timeval *timeout) { // ;-) #define ENOUGH_DATA_FOR_PARSING 64 fd_set events; memset(event, 0, sizeof(struct tb_event)); // try to extract event from input buffer, return on success event->type = TB_EVENT_KEY; if (extract_event(event, &input_buffer, inputmode)) return TB_EVENT_KEY; // it looks like input buffer is incomplete, let's try the short path, // but first make sure there is enough space int prevlen = input_buffer.len; bytebuffer_resize(&input_buffer, prevlen + ENOUGH_DATA_FOR_PARSING); ssize_t r = read(inout, input_buffer.buf + prevlen, ENOUGH_DATA_FOR_PARSING); if (r < 0) { // EAGAIN / EWOULDBLOCK shouldn't occur here assert(errno != EAGAIN && errno != EWOULDBLOCK); return -1; } else if (r > 0) { bytebuffer_resize(&input_buffer, prevlen + r); if (extract_event(event, &input_buffer, inputmode)) return TB_EVENT_KEY; } else { bytebuffer_resize(&input_buffer, prevlen); } // r == 0, or not enough data, let's go to select while (1) { FD_ZERO(&events); FD_SET(inout, &events); FD_SET(winch_fds[0], &events); int maxfd = (winch_fds[0] > inout) ? winch_fds[0] : inout; int result = select(maxfd+1, &events, 0, 0, timeout); if (!result) return 0; if (FD_ISSET(inout, &events)) { event->type = TB_EVENT_KEY; prevlen = input_buffer.len; bytebuffer_resize(&input_buffer, prevlen + ENOUGH_DATA_FOR_PARSING); r = read(inout, input_buffer.buf + prevlen, ENOUGH_DATA_FOR_PARSING); if (r < 0) { // EAGAIN / EWOULDBLOCK shouldn't occur here assert(errno != EAGAIN && errno != EWOULDBLOCK); return -1; } assert(r > 0); bytebuffer_resize(&input_buffer, prevlen + r); if (extract_event(event, &input_buffer, inputmode)) return TB_EVENT_KEY; } if (FD_ISSET(winch_fds[0], &events)) { event->type = TB_EVENT_RESIZE; int zzz = 0; read(winch_fds[0], &zzz, sizeof(int)); buffer_size_change_request = 1; get_term_size(&event->w, &event->h); return TB_EVENT_RESIZE; } } }