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

Contents of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.30 - (show annotations)
Tue May 13 02:19:15 2025 UTC (10 months ago) by sysadm
Branch: MAIN
Changes since 1.29: +51 -14 lines
Content type: text/x-csrc
Refine prints / outc, flush buffer while no enough free space

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 static int stdout_buf_offset = 0;
34
35 int prints(const char *format, ...)
36 {
37 char buf[BUFSIZ];
38 va_list args;
39 int ret;
40
41 va_start(args, format);
42 ret = vsnprintf(buf, sizeof(buf), format, args);
43 va_end(args);
44
45 if (ret > 0)
46 {
47 if (stdout_buf_len + ret > BUFSIZ)
48 {
49 iflush();
50 }
51
52 if (stdout_buf_len + ret <= BUFSIZ)
53 {
54 memcpy(stdout_buf + stdout_buf_len, buf, (size_t)ret);
55 stdout_buf_len += ret;
56 }
57 else
58 {
59 errno = EAGAIN;
60 ret = (BUFSIZ - stdout_buf_len - ret);
61 }
62 }
63
64 return ret;
65 }
66
67 int outc(char c)
68 {
69 int ret;
70
71 if (stdout_buf_len + 1 > BUFSIZ)
72 {
73 iflush();
74 }
75
76 if (stdout_buf_len + 1 <= BUFSIZ)
77 {
78 stdout_buf[stdout_buf_len] = c;
79 stdout_buf_len++;
80 }
81 else
82 {
83 errno = EAGAIN;
84 ret = -1;
85 }
86
87 return ret;
88 }
89
90 int iflush()
91 {
92 int flags;
93 struct epoll_event ev, events[MAX_EVENTS];
94 int nfds, epollfd;
95 int retry;
96 int ret = 0;
97
98 epollfd = epoll_create1(0);
99 if (epollfd < 0)
100 {
101 log_error("epoll_create1() error (%d)\n", errno);
102 return -1;
103 }
104
105 ev.events = EPOLLOUT;
106 ev.data.fd = STDOUT_FILENO;
107 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDOUT_FILENO, &ev) == -1)
108 {
109 log_error("epoll_ctl(STDOUT_FILENO) error (%d)\n", errno);
110 return -1;
111 }
112
113 // Set STDOUT as non-blocking
114 flags = fcntl(STDOUT_FILENO, F_GETFL, 0);
115 fcntl(STDOUT_FILENO, F_SETFL, flags | O_NONBLOCK);
116
117 // Retry wait / flush for at most 3 times
118 retry = 3;
119 while (retry > 0 && !SYS_server_exit)
120 {
121 retry--;
122
123 nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); // 0.1 second
124
125 if (nfds < 0)
126 {
127 if (errno != EINTR)
128 {
129 log_error("epoll_wait() error (%d)\n", errno);
130 break;
131 }
132 continue;
133 }
134 else if (nfds == 0) // timeout
135 {
136 continue;
137 }
138
139 for (int i = 0; i < nfds; i++)
140 {
141 if (events[i].data.fd == STDOUT_FILENO)
142 {
143 while (stdout_buf_offset < stdout_buf_len && !SYS_server_exit) // write until complete or error
144 {
145 ret = (int)write(STDOUT_FILENO, stdout_buf + stdout_buf_offset, (size_t)(stdout_buf_len - stdout_buf_offset));
146 if (ret < 0)
147 {
148 if (errno == EAGAIN || errno == EWOULDBLOCK)
149 {
150 break;
151 }
152 else if (errno == EINTR)
153 {
154 continue;
155 }
156 else
157 {
158 log_error("write(STDOUT) error (%d)\n", errno);
159 retry = 0;
160 break;
161 }
162 }
163 else if (ret == 0) // broken pipe
164 {
165 retry = 0;
166 break;
167 }
168 else
169 {
170 stdout_buf_offset += ret;
171 if (stdout_buf_offset >= stdout_buf_len) // flush buffer completely
172 {
173 ret = 0;
174 stdout_buf_offset = 0;
175 stdout_buf_len = 0;
176 retry = 0;
177 break;
178 }
179 continue;
180 }
181 }
182 }
183 }
184 }
185
186 // Restore STDOUT flags
187 fcntl(STDOUT_FILENO, F_SETFL, flags);
188
189 return ret;
190 }
191
192 int igetch(int clear_buf)
193 {
194 // static input buffer
195 static unsigned char buf[LINE_BUFFER_LEN];
196 static ssize_t len = 0;
197 static int pos = 0;
198
199 struct epoll_event ev, events[MAX_EVENTS];
200 int nfds, epollfd;
201
202 unsigned char tmp[LINE_BUFFER_LEN];
203 int out = '\0';
204 int in_esc = 0;
205 int in_ascii = 0;
206 int in_control = 0;
207 int i = 0;
208 int flags;
209
210 if (clear_buf)
211 {
212 pos = 0;
213 len = 0;
214
215 return '\0';
216 }
217
218 epollfd = epoll_create1(0);
219 if (epollfd < 0)
220 {
221 log_error("epoll_create1() error (%d)\n", errno);
222 return -1;
223 }
224
225 ev.events = EPOLLIN;
226 ev.data.fd = STDIN_FILENO;
227 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) == -1)
228 {
229 log_error("epoll_ctl(STDIN_FILENO) error (%d)\n", errno);
230 return -1;
231 }
232
233 flags = fcntl(STDIN_FILENO, F_GETFL, 0);
234 fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
235
236 while (!SYS_server_exit && pos >= len)
237 {
238 nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); // 0.1 second
239
240 if (nfds < 0)
241 {
242 if (errno != EINTR)
243 {
244 log_error("epoll_wait() error (%d)\n", errno);
245 fcntl(STDIN_FILENO, F_SETFL, flags);
246 return KEY_NULL;
247 }
248 continue;
249 }
250 else if (nfds == 0)
251 {
252 fcntl(STDIN_FILENO, F_SETFL, flags);
253 return KEY_TIMEOUT;
254 }
255
256 for (int i = 0; i < nfds; i++)
257 {
258 if (events[i].data.fd == STDIN_FILENO)
259 {
260 while (!SYS_server_exit) // read until complete or error
261 {
262 len = read(STDIN_FILENO, buf, sizeof(buf));
263 if (len < 0)
264 {
265 if (errno == EAGAIN || errno == EWOULDBLOCK)
266 {
267 fcntl(STDIN_FILENO, F_SETFL, flags);
268 return KEY_TIMEOUT;
269 }
270 else if (errno == EINTR)
271 {
272 continue;
273 }
274 else
275 {
276 log_error("read(STDIN) error (%d)\n", errno);
277 fcntl(STDIN_FILENO, F_SETFL, flags);
278 return KEY_NULL;
279 }
280 }
281 else if (len == 0) // broken pipe
282 {
283 fcntl(STDIN_FILENO, F_SETFL, flags);
284 return KEY_NULL;
285 }
286
287 pos = 0;
288 break;
289 }
290 }
291 }
292
293 // For debug
294 // for (j = 0; j < len; j++)
295 // log_std ("<--[%u]\n", (buf[j] + 256) % 256);
296 }
297
298 fcntl(STDIN_FILENO, F_SETFL, flags);
299
300 while (pos < len)
301 {
302 unsigned char c = buf[pos++];
303
304 if (c == KEY_CONTROL)
305 {
306 if (in_control == 0)
307 {
308 in_control = 1;
309 i = 0;
310 continue;
311 }
312 }
313
314 if (in_control)
315 {
316 tmp[i++] = c;
317 if (i >= 2)
318 {
319 out = (int)tmp[0] * 256 + tmp[1];
320 in_control = 0;
321 break;
322 }
323 continue;
324 }
325
326 if (c == ESC_KEY)
327 {
328 if (in_esc == 0)
329 {
330 in_esc = 1;
331 in_ascii = 1;
332 i = 0;
333 continue;
334 }
335 else
336 {
337 out = ESC_KEY;
338 in_esc = 0;
339 break;
340 }
341 }
342
343 in_esc = 0;
344
345 if (in_ascii)
346 {
347 tmp[i++] = c;
348 if (c == 'm')
349 {
350 in_ascii = 0;
351 continue;
352 }
353 if (i == 2 && c >= 'A' && c <= 'D')
354 {
355 in_ascii = 0;
356 switch (c)
357 {
358 case 'A':
359 out = KEY_UP;
360 break;
361 case 'B':
362 out = KEY_DOWN;
363 break;
364 case 'C':
365 out = KEY_RIGHT;
366 break;
367 case 'D':
368 out = KEY_LEFT;
369 break;
370 }
371 break;
372 }
373 if (i == 3 && tmp[0] == 91 && tmp[2] == 126)
374 {
375 in_ascii = 0;
376 switch (tmp[1])
377 {
378 case 49:
379 out = KEY_HOME;
380 break;
381 case 51:
382 out = KEY_DEL;
383 break;
384 case 52:
385 out = KEY_END;
386 break;
387 case 53:
388 out = KEY_PGUP;
389 break;
390 case 54:
391 out = KEY_PGDN;
392 break;
393 }
394 break;
395 }
396 continue;
397 }
398
399 out = ((int)c + 256) % 256;
400 break;
401 }
402
403 // for debug
404 // log_std ("-->[%u]\n", out);
405
406 return out;
407 }
408
409 int igetch_t(long int sec)
410 {
411 int ch;
412 time_t t_begin = time(0);
413
414 do
415 {
416 ch = igetch(0);
417 } while (!SYS_server_exit && ch == KEY_TIMEOUT && (time(0) - t_begin < sec));
418
419 return ch;
420 }

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