diff options
Diffstat (limited to 'linux/main.c')
| -rw-r--r-- | linux/main.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/linux/main.c b/linux/main.c new file mode 100644 index 0000000..bd208f2 --- /dev/null +++ b/linux/main.c @@ -0,0 +1,132 @@ +#include <stdio.h> +#include <termios.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <poll.h> + +#ifdef DEBUG_MESSAGE +#define DEBUG(_s, ...) fprintf(stderr, _s, ## __VA_ARGS__) +#else +#define DEBUG(_s, ...) +#endif + +#define elt0(_exp) ((_exp) < 0) +#define check(_x, _cond, ...) do { if (_cond(_x)) { fatal_error(__VA_ARGS__); } } while (0) +#define fatal_error(...) do { fprintf(stderr, __VA_ARGS__); exit(1); } while (0) + +#define GECKO_BAUD B115200 + +static int setup_term(const char *name) { + int fd; + int flags; + struct termios tio; + +#define O(_ex, _m) check(_ex, elt0, "error " _m " %s: %s\n", name, strerror(errno)) + + O(fd = openat(AT_FDCWD, name, O_RDWR | O_NOCTTY), "opening"); + O(tcgetattr(fd, &tio), "getting tio attrs for"); + O(cfsetispeed(&tio, GECKO_BAUD), "setting ispeed of"); + O(cfsetospeed(&tio, GECKO_BAUD), "setting ospeed of"); + + tio.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + tio.c_oflag &= ~OPOST; + tio.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + tio.c_cflag &= ~(CSIZE | PARENB); + tio.c_cflag |= CS8; + + O(tcsetattr(fd, TCSANOW, &tio), "setting tio attrs for"); + + O(flags = fcntl(fd, F_GETFL), "getting stream status for"); + flags |= O_NONBLOCK; + O(fcntl(fd, F_SETFL, flags), "setting stream status for"); + +#undef O + + return fd; +} + +static void handle_command(const char *cmd) { + +} + +int main(int argc, char **argv) { + struct termios tio; + int tfd; + unsigned char buf[1024]; + char cmdbuf[1024]; + struct pollfd fds[2]; + int infd; + int flags; + int can_write = 0; + size_t partialcmd_sz = 0; + + int test_mode = 0; + + if (argc != 2) { + fprintf(stderr, "Usage: %s <term>\n", argv[0]); + return 1; + } + + tfd = setup_term(argv[1]); + + check(infd = dup(STDIN_FILENO), elt0, "error duplicating stdin: %s\n", strerror(errno)); + check(flags = fcntl(infd, F_GETFL), elt0, "error getting stream status for stdin: %s\n", strerror(errno)); + flags |= O_NONBLOCK; + check(fcntl(infd, F_SETFL, flags), elt0, "setting stream status for stdin: %s\n", strerror(errno)); + + fds[0].fd = tfd; + fds[0].events = POLLIN | POLLOUT; + + fds[1].fd = STDIN_FILENO; + fds[1].events = POLLIN; + + while (1) { + int nready; + check(nready = poll(fds, 2, -1), elt0, "poll()ing: %s\n", strerror(errno)); + + if (nready == 0) continue; + + for (nfds_t i = 0; i < 2; ++i) { + if (fds[i].revents & (POLLERR | POLLHUP)) { + fatal_error("stream error or hangup condition on %d\n", fds[i].fd); + } + + if (fds[i].revents & POLLIN) { + ssize_t nread; + while ((nread = read(fds[i].fd, buf, 1024)) > 0) { + if (fds[i].fd == infd) { + /* command */ + for (ssize_t cidx = 0; cidx < nread; ++i) { + /* TODO: split command by lines */ + } + } else { + /* gecko */ + + } + check(write(STDOUT_FILENO, buf, nread), elt0, "write(%d) failed: %s\n", STDOUT_FILENO, strerror(errno)); + } + + if (nread == 0 && fds[i].fd == tfd) { + fatal_error("EOF reached on terminal.\n"); + } + + if (nread < 0 && errno != EAGAIN) { + fatal_error("io error on fd %d: %s\n", fds[i].fd, strerror(errno)); + } + } + + if (fds[i].revents & POLLOUT) { + fds[i].events &= ~POLLOUT; + can_write = 1; + } + } + } + + close(tfd); + close(infd); + + return 0; +} |
