/* cat.c - example cat program * * Copyright (C) 2007 Ray Strode * * This program is public domain. You may use or modify it however * you want, but it comes without warranty of any kind. * * See * http://blogs.gnome.org/halfline/2007/07/25/calling-io-functions-in-a-loop/ */ #include #include #include #include #include #include static bool wait_on_fds (int input_fd, bool *input_ready, bool *input_eof, int output_fd, bool *output_ready) { struct pollfd poll_data[2] = { 0 }; int fd_count, i, result_count; i = 0; if (output_fd >= 0) { poll_data[i].fd = output_fd; poll_data[i].events = POLLOUT; poll_data[i].revents = 0; i++; *output_ready = false; } if (input_fd >= 0) { poll_data[i].fd = input_fd; poll_data[i].events = POLLIN; poll_data[i].revents = 0; i++; *input_ready = false; *input_eof = false; } fd_count = i; result_count = poll (poll_data, fd_count, -1); for (i = 0; i < result_count; i++) { if (poll_data[i].fd == output_fd) { *output_ready = poll_data[i].revents & POLLOUT; if (poll_data[i].revents & POLLERR) return false; } else if (poll_data[i].fd == input_fd) { *input_ready = poll_data[i].revents & POLLIN; *input_eof = poll_data[i].revents & POLLHUP; } } return result_count > 0; } static bool read_into_buffer (int input_fd, char *buffer, size_t buffer_size, ssize_t *bytes_read, bool *got_eof) { *bytes_read = read (input_fd, buffer, buffer_size); if (*bytes_read < 0) { if (errno == EINTR) *bytes_read = 0; else if (errno != EAGAIN) return false; } else if (*bytes_read == 0) *got_eof = true; return true; } static bool write_from_buffer (int output_fd, const char *buffer, size_t buffer_size, ssize_t *bytes_written) { *bytes_written = write (output_fd, buffer, buffer_size); if (*bytes_written < 0) return false; return true; } bool cat (int input_fd, int output_fd) { size_t begin_index, end_index; char buffer[4096]; bool got_eof = false; bool buffer_has_room = true, buffer_has_data = false; bool input_ready, output_ready; memset (buffer, '\0', sizeof (buffer)); begin_index = 0; end_index = 0; while (wait_on_fds (buffer_has_room? input_fd : -1, &input_ready, &got_eof, buffer_has_data? output_fd : -1, &output_ready)) { ssize_t bytes_written, bytes_read; int result; if (buffer_has_room && input_ready) { if (!read_into_buffer (input_fd, buffer + end_index, sizeof (buffer) - end_index, &bytes_read, &got_eof)) break; end_index += bytes_read; } if (got_eof) { input_ready = false; input_fd = -1; } if (buffer_has_data && output_ready) { if (!write_from_buffer (output_fd, buffer + begin_index, end_index - begin_index, &bytes_written)) break; begin_index += bytes_written; } if (begin_index >= end_index) { buffer_has_room = true; begin_index = 0; end_index = 0; } else if (end_index >= sizeof (buffer)) buffer_has_room = false; buffer_has_data = end_index > begin_index; if (!buffer_has_data && got_eof) return true; } return false; } int main (int argc, char **argv) { if (!cat (STDIN_FILENO, STDOUT_FILENO)) return 1; return 0; }