/[LeafOK_CVS]/lbbs/src/io.c
ViewVC logotype

Contents of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.29 - (show annotations)
Mon May 12 09:41:50 2025 UTC (10 months ago) by sysadm
Branch: MAIN
Changes since 1.28: +123 -66 lines
Content type: text/x-csrc
Refact IO with epoll

1 /***************************************************************************
2 io.c - description
3 -------------------
4 Copyright : (C) 2004-2025 by Leaflet
5 Email : leaflet@leafok.com
6 ***************************************************************************/
7
8 /***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 3 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16
17 #include "io.h"
18 #include "log.h"
19 #include "common.h"
20 #include <errno.h>
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <time.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <sys/select.h>
28 #include <sys/ioctl.h>
29 #include <sys/epoll.h>
30
31 static char stdout_buf[BUFSIZ];
32 static int stdout_buf_len = 0;
33
34 int prints(const char *format, ...)
35 {
36 char buf[BUFSIZ];
37 va_list args;
38 int ret;
39
40 va_start(args, format);
41 ret = vsnprintf(buf, sizeof(buf), format, args);
42 va_end(args);
43
44 if (ret > 0 && stdout_buf_len + ret < BUFSIZ)
45 {
46 memcpy(stdout_buf + stdout_buf_len, buf, (size_t)(ret + 1));
47 stdout_buf_len += ret;
48 }
49 else if (ret > 0) // No enough free buffer
50 {
51 ret = (BUFSIZ - stdout_buf_len - ret - 1);
52 }
53
54 return ret;
55 }
56
57 int iflush()
58 {
59 int flags;
60 struct epoll_event ev, events[MAX_EVENTS];
61 int nfds, epollfd;
62 int stdout_buf_offset = 0;
63 int loop = 1;
64 int ret = 0;
65
66 epollfd = epoll_create1(0);
67 if (epollfd < 0)
68 {
69 log_error("epoll_create1() error (%d)\n", errno);
70 return -1;
71 }
72
73 ev.events = EPOLLOUT;
74 ev.data.fd = STDOUT_FILENO;
75 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDOUT_FILENO, &ev) == -1)
76 {
77 log_error("epoll_ctl(STDOUT_FILENO) error (%d)\n", errno);
78 return -1;
79 }
80
81 // Set STDOUT as non-blocking
82 flags = fcntl(STDOUT_FILENO, F_GETFL, 0);
83 fcntl(STDOUT_FILENO, F_SETFL, flags | O_NONBLOCK);
84
85 while (loop && !SYS_server_exit)
86 {
87 nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); // 0.1 second
88
89 if (nfds < 0)
90 {
91 if (errno != EINTR)
92 {
93 log_error("epoll_wait() error (%d)\n", errno);
94 break;
95 }
96 continue;
97 }
98 else if (nfds == 0) // timeout
99 {
100 continue;
101 }
102
103 for (int i = 0; i < nfds; i++)
104 {
105 if (events[i].data.fd == STDOUT_FILENO)
106 {
107 while (1) // write until complete or error
108 {
109 ret = (int)write(STDOUT_FILENO, stdout_buf + stdout_buf_offset, (size_t)(stdout_buf_len - stdout_buf_offset));
110 if (ret < 0)
111 {
112 if (errno == EAGAIN || errno == EWOULDBLOCK)
113 {
114 break;
115 }
116 else if (errno == EINTR)
117 {
118 continue;
119 }
120 else
121 {
122 log_error("write(STDOUT) error (%d)\n", errno);
123 loop = 0;
124 break;
125 }
126 }
127 else if (ret == 0) // broken pipe
128 {
129 loop = 0;
130 break;
131 }
132 else
133 {
134 stdout_buf_offset += ret;
135 if (stdout_buf_offset >= stdout_buf_len) // Flush buffer complete
136 {
137 ret = 0;
138 stdout_buf_len = 0;
139 loop = 0;
140 break;
141 }
142 continue;
143 }
144 }
145 }
146 }
147 }
148
149 // Restore STDOUT flags
150 fcntl(STDOUT_FILENO, F_SETFL, flags);
151
152 return ret;
153 }
154
155 int igetch(int clear_buf)
156 {
157 // static input buffer
158 static unsigned char buf[LINE_BUFFER_LEN];
159 static ssize_t len = 0;
160 static int pos = 0;
161
162 struct epoll_event ev, events[MAX_EVENTS];
163 int nfds, epollfd;
164
165 unsigned char tmp[LINE_BUFFER_LEN];
166 int out = '\0';
167 int in_esc = 0;
168 int in_ascii = 0;
169 int in_control = 0;
170 int i = 0;
171 int flags;
172
173 if (clear_buf)
174 {
175 pos = 0;
176 len = 0;
177
178 return '\0';
179 }
180
181 epollfd = epoll_create1(0);
182 if (epollfd < 0)
183 {
184 log_error("epoll_create1() error (%d)\n", errno);
185 return -1;
186 }
187
188 ev.events = EPOLLIN;
189 ev.data.fd = STDIN_FILENO;
190 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) == -1)
191 {
192 log_error("epoll_ctl(STDIN_FILENO) error (%d)\n", errno);
193 return -1;
194 }
195
196 flags = fcntl(STDIN_FILENO, F_GETFL, 0);
197 fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
198
199 while (!SYS_server_exit && pos >= len)
200 {
201 nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); // 0.1 second
202
203 if (nfds < 0)
204 {
205 if (errno != EINTR)
206 {
207 log_error("epoll_wait() error (%d)\n", errno);
208 fcntl(STDIN_FILENO, F_SETFL, flags);
209 return KEY_NULL;
210 }
211 continue;
212 }
213 else if (nfds == 0)
214 {
215 fcntl(STDIN_FILENO, F_SETFL, flags);
216 return KEY_TIMEOUT;
217 }
218
219 for (int i = 0; i < nfds; i++)
220 {
221 if (events[i].data.fd == STDIN_FILENO)
222 {
223 while (1) // read until complete or error
224 {
225 len = read(STDIN_FILENO, buf, sizeof(buf));
226 if (len < 0)
227 {
228 if (errno == EAGAIN || errno == EWOULDBLOCK)
229 {
230 fcntl(STDIN_FILENO, F_SETFL, flags);
231 return KEY_TIMEOUT;
232 }
233 else if (errno == EINTR)
234 {
235 continue;
236 }
237 else
238 {
239 log_error("read(STDIN) error (%d)\n", errno);
240 fcntl(STDIN_FILENO, F_SETFL, flags);
241 return KEY_NULL;
242 }
243 }
244 else if (len == 0) // broken pipe
245 {
246 fcntl(STDIN_FILENO, F_SETFL, flags);
247 return KEY_NULL;
248 }
249
250 pos = 0;
251 break;
252 }
253 }
254 }
255
256 // For debug
257 // for (j = 0; j < len; j++)
258 // log_std ("<--[%u]\n", (buf[j] + 256) % 256);
259 }
260
261 fcntl(STDIN_FILENO, F_SETFL, flags);
262
263 while (pos < len)
264 {
265 unsigned char c = buf[pos++];
266
267 if (c == KEY_CONTROL)
268 {
269 if (in_control == 0)
270 {
271 in_control = 1;
272 i = 0;
273 continue;
274 }
275 }
276
277 if (in_control)
278 {
279 tmp[i++] = c;
280 if (i >= 2)
281 {
282 out = (int)tmp[0] * 256 + tmp[1];
283 in_control = 0;
284 break;
285 }
286 continue;
287 }
288
289 if (c == ESC_KEY)
290 {
291 if (in_esc == 0)
292 {
293 in_esc = 1;
294 in_ascii = 1;
295 i = 0;
296 continue;
297 }
298 else
299 {
300 out = ESC_KEY;
301 in_esc = 0;
302 break;
303 }
304 }
305
306 in_esc = 0;
307
308 if (in_ascii)
309 {
310 tmp[i++] = c;
311 if (c == 'm')
312 {
313 in_ascii = 0;
314 continue;
315 }
316 if (i == 2 && c >= 'A' && c <= 'D')
317 {
318 in_ascii = 0;
319 switch (c)
320 {
321 case 'A':
322 out = KEY_UP;
323 break;
324 case 'B':
325 out = KEY_DOWN;
326 break;
327 case 'C':
328 out = KEY_RIGHT;
329 break;
330 case 'D':
331 out = KEY_LEFT;
332 break;
333 }
334 break;
335 }
336 if (i == 3 && tmp[0] == 91 && tmp[2] == 126)
337 {
338 in_ascii = 0;
339 switch (tmp[1])
340 {
341 case 49:
342 out = KEY_HOME;
343 break;
344 case 51:
345 out = KEY_DEL;
346 break;
347 case 52:
348 out = KEY_END;
349 break;
350 case 53:
351 out = KEY_PGUP;
352 break;
353 case 54:
354 out = KEY_PGDN;
355 break;
356 }
357 break;
358 }
359 continue;
360 }
361
362 out = ((int)c + 256) % 256;
363 break;
364 }
365
366 // for debug
367 // log_std ("-->[%u]\n", out);
368
369 return out;
370 }
371
372 int igetch_t(long int sec)
373 {
374 int ch;
375 time_t t_begin = time(0);
376
377 do
378 {
379 ch = igetch(0);
380 } while (!SYS_server_exit && ch == KEY_TIMEOUT && (time(0) - t_begin < sec));
381
382 return ch;
383 }

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1