/// Sets the stream associated with `fd` to "blocking" mode. /// /// @return `0` on success, or libuv error code on failure. int stream_set_blocking(int fd, bool blocking) { // Private loop to avoid conflict with existing watcher(s): // uv__io_stop: Assertion `loop->watchers[w->fd] == w' failed. uv_loop_t loop; uv_pipe_t stream; uv_loop_init(&loop); uv_pipe_init(&loop, &stream, 0); uv_pipe_open(&stream, fd); int retval = uv_stream_set_blocking(STRUCT_CAST(uv_stream_t, &stream), blocking); uv_close(STRUCT_CAST(uv_handle_t, &stream), NULL); uv_run(&loop, UV_RUN_NOWAIT); // not necessary, but couldn't hurt. uv_loop_close(&loop); return retval; }
static void read_cb(uv_stream_t *stream, ssize_t cnt, const uv_buf_t *buf) { if (cnt <= 0) { uv_read_stop(stream); return; } int *interrupted = stream->data; for (int i = 0; i < cnt; i++) { if (buf->base[i] == CTRL_C) { (*interrupted)++; } } uv_loop_t write_loop; uv_loop_init(&write_loop); uv_tty_t out; uv_tty_init(&write_loop, &out, fileno(stdout), 0); uv_write_t req; uv_buf_t b = { .base = buf->base, #ifdef WIN32 .len = (ULONG)cnt #else .len = (size_t)cnt #endif }; uv_write(&req, STRUCT_CAST(uv_stream_t, &out), &b, 1, NULL); uv_run(&write_loop, UV_RUN_DEFAULT); uv_close(STRUCT_CAST(uv_handle_t, &out), NULL); uv_run(&write_loop, UV_RUN_DEFAULT); if (uv_loop_close(&write_loop)) { abort(); } free(buf->base); if (*interrupted >= 2) { uv_walk(uv_default_loop(), walk_cb, NULL); } else if (*interrupted == 1) { fprintf(stderr, "interrupt received, press again to exit\n"); } }
int main(int argc, char **argv) { if (!owns_tty()) { fprintf(stderr, "process does not own the terminal\n"); exit(2); } if (!is_terminal(stdin)) { fprintf(stderr, "stdin is not a terminal\n"); exit(2); } if (!is_terminal(stdout)) { fprintf(stderr, "stdout is not a terminal\n"); exit(2); } if (!is_terminal(stderr)) { fprintf(stderr, "stderr is not a terminal\n"); exit(2); } if (argc > 1) { errno = 0; int count = (int)strtol(argv[1], NULL, 10); if (errno != 0) { abort(); } count = (count < 0 || count > 99999) ? 0 : count; for (int i = 0; i < count; i++) { printf("line%d\n", i); } fflush(stdout); return 0; } int interrupted = 0; uv_prepare_t prepare; uv_prepare_init(uv_default_loop(), &prepare); uv_prepare_start(&prepare, prepare_cb); #ifndef WIN32 uv_tty_init(uv_default_loop(), &tty, fileno(stderr), 1); #else uv_tty_init(uv_default_loop(), &tty, fileno(stdin), 1); uv_tty_init(uv_default_loop(), &tty_out, fileno(stdout), 0); int width, height; uv_tty_get_winsize(&tty_out, &width, &height); #endif uv_tty_set_mode(&tty, UV_TTY_MODE_RAW); tty.data = &interrupted; uv_read_start(STRUCT_CAST(uv_stream_t, &tty), alloc_cb, read_cb); #ifndef WIN32 struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = sig_handler; sigaction(SIGHUP, &sa, NULL); sigaction(SIGWINCH, &sa, NULL); #else uv_signal_t sigwinch_watcher; uv_signal_init(uv_default_loop(), &sigwinch_watcher); uv_signal_start(&sigwinch_watcher, sigwinch_cb, SIGWINCH); #endif uv_run(uv_default_loop(), UV_RUN_DEFAULT); #ifndef WIN32 // XXX: Without this the SIGHUP handler is skipped on some systems. sleep(100); #endif return 0; }