Added uxsel.c, into which I've moved those parts of the uxnet.c
[sgt/putty] / unix / uxsel.c
diff --git a/unix/uxsel.c b/unix/uxsel.c
new file mode 100644 (file)
index 0000000..aaedc02
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * uxsel.c
+ * 
+ * This module is a sort of all-purpose interchange for file
+ * descriptors. At one end it talks to uxnet.c and pty.c and
+ * anything else which might have one or more fds that need
+ * select()-type things doing to them during an extended program
+ * run; at the other end it talks to pterm.c or uxplink.c or
+ * anything else which might have its own means of actually doing
+ * those select()-type things.
+ */
+
+#include <assert.h>
+
+#include "putty.h"
+#include "tree234.h"
+
+struct fd {
+    int fd;
+    int rwx;                          /* 4=except 2=write 1=read */
+    uxsel_callback_fn callback;
+};
+
+static tree234 *fds;
+
+static int uxsel_fd_cmp(void *av, void *bv)
+{
+    struct fd *a = (struct fd *)av;
+    struct fd *b = (struct fd *)bv;
+    if (a->fd < b->fd)
+       return -1;
+    if (a->fd > b->fd)
+       return +1;
+    return 0;
+}
+static int uxsel_fd_findcmp(void *av, void *bv)
+{
+    int *a = (int *)av;
+    struct fd *b = (struct fd *)bv;
+    if (*a < b->fd)
+       return -1;
+    if (*a > b->fd)
+       return +1;
+    return 0;
+}
+
+void uxsel_init(void)
+{
+    fds = newtree234(uxsel_fd_cmp);
+}
+
+/*
+ * Here is the interface to fd-supplying modules. They supply an
+ * fd, a set of read/write/execute states, and a callback function
+ * for when the fd satisfies one of those states. Repeated calls to
+ * uxsel_set on the same fd are perfectly legal and serve to change
+ * the rwx state (typically you only want to select an fd for
+ * writing when you actually have pending data you want to write to
+ * it!).
+ */
+
+void uxsel_set(int fd, int rwx, uxsel_callback_fn callback)
+{
+    struct fd *newfd = snew(struct fd);
+    struct fd *oldfd;
+
+    newfd->fd = fd;
+    newfd->rwx = rwx;
+    newfd->callback = callback;
+
+    oldfd = find234(fds, newfd, NULL);
+    if (oldfd) {
+       del234(fds, oldfd);
+       sfree(oldfd);
+    }
+
+    add234(fds, newfd);
+}
+
+void uxsel_del(int fd)
+{
+    struct fd *oldfd = find234(fds, &fd, uxsel_fd_findcmp);
+    if (oldfd) {
+       del234(fds, oldfd);
+       sfree(oldfd);
+    }
+}
+
+/*
+ * And here is the interface to select-functionality-supplying
+ * modules. 
+ */
+
+int next_fd(int *state, int *rwx)
+{
+    struct fd *fd;
+    fd = index234(fds, (*state)++);
+    if (fd) {
+       *rwx = fd->rwx;
+       return fd->fd;
+    } else
+       return -1;
+}
+
+int first_fd(int *state, int *rwx)
+{
+    *state = 0;
+    return next_fd(state, rwx);
+}
+
+int select_result(int fd, int event)
+{
+    struct fd *fdstruct = find234(fds, &fd, uxsel_fd_findcmp);
+    assert(fdstruct != NULL);
+    return fdstruct->callback(fd, event);
+}