OSDN Git Service

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