]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - unix/uxsel.c
first pass
[PuTTY.git] / unix / uxsel.c
1 /*
2  * uxsel.c
3  * 
4  * This module is a sort of all-purpose interchange for file
5  * descriptors. At one end it talks to uxnet.c and pty.c and
6  * anything else which might have one or more fds that need
7  * select()-type things doing to them during an extended program
8  * run; at the other end it talks to pterm.c or uxplink.c or
9  * anything else which might have its own means of actually doing
10  * those select()-type things.
11  */
12
13 #include <assert.h>
14
15 #include "putty.h"
16 #include "tree234.h"
17
18 struct fd {
19     int fd;
20     int rwx;                           /* 4=except 2=write 1=read */
21     uxsel_callback_fn callback;
22     uxsel_id *id;                      /* for uxsel_input_remove */
23 };
24
25 static tree234 *fds;
26
27 static int uxsel_fd_cmp(void *av, void *bv)
28 {
29     struct fd *a = (struct fd *)av;
30     struct fd *b = (struct fd *)bv;
31     if (a->fd < b->fd)
32         return -1;
33     if (a->fd > b->fd)
34         return +1;
35     return 0;
36 }
37 static int uxsel_fd_findcmp(void *av, void *bv)
38 {
39     int *a = (int *)av;
40     struct fd *b = (struct fd *)bv;
41     if (*a < b->fd)
42         return -1;
43     if (*a > b->fd)
44         return +1;
45     return 0;
46 }
47
48 void uxsel_init(void)
49 {
50     fds = newtree234(uxsel_fd_cmp);
51 }
52
53 /*
54  * Here is the interface to fd-supplying modules. They supply an
55  * fd, a set of read/write/execute states, and a callback function
56  * for when the fd satisfies one of those states. Repeated calls to
57  * uxsel_set on the same fd are perfectly legal and serve to change
58  * the rwx state (typically you only want to select an fd for
59  * writing when you actually have pending data you want to write to
60  * it!).
61  */
62
63 void uxsel_set(int fd, int rwx, uxsel_callback_fn callback)
64 {
65     struct fd *newfd;
66
67     assert(fd >= 0);
68
69     uxsel_del(fd);
70
71     if (rwx) {
72         newfd = snew(struct fd);
73         newfd->fd = fd;
74         newfd->rwx = rwx;
75         newfd->callback = callback;
76         newfd->id = uxsel_input_add(fd, rwx);
77         add234(fds, newfd);
78     }
79 }
80
81 void uxsel_del(int fd)
82 {
83     struct fd *oldfd = find234(fds, &fd, uxsel_fd_findcmp);
84     if (oldfd) {
85         if (oldfd->id)
86             uxsel_input_remove(oldfd->id);
87         del234(fds, oldfd);
88         sfree(oldfd);
89     }
90 }
91
92 /*
93  * And here is the interface to select-functionality-supplying
94  * modules. 
95  */
96
97 int next_fd(int *state, int *rwx)
98 {
99     struct fd *fd;
100     fd = index234(fds, (*state)++);
101     if (fd) {
102         *rwx = fd->rwx;
103         return fd->fd;
104     } else
105         return -1;
106 }
107
108 int first_fd(int *state, int *rwx)
109 {
110     *state = 0;
111     return next_fd(state, rwx);
112 }
113
114 int select_result(int fd, int event)
115 {
116     struct fd *fdstruct = find234(fds, &fd, uxsel_fd_findcmp);
117     /*
118      * Apparently this can sometimes be NULL. Can't see how, but I
119      * assume it means I need to ignore the event since it's on an
120      * fd I've stopped being interested in. Sigh.
121      */
122     if (fdstruct)
123         return fdstruct->callback(fd, event);
124     else
125         return 1;
126 }