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

Contents of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.28 - (show annotations)
Sun May 11 14:52:26 2025 UTC (10 months ago) by sysadm
Branch: MAIN
Changes since 1.27: +85 -19 lines
Content type: text/x-csrc
Refact format output with non-blocking socket write

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
30 static char stdout_buf[BUFSIZ];
31 static int stdout_buf_len = 0;
32
33 int prints(const char *format, ...)
34 {
35 char buf[BUFSIZ];
36 va_list args;
37 int ret;
38
39 va_start(args, format);
40 ret = vsnprintf(buf, sizeof(buf), format, args);
41 va_end(args);
42
43 if (ret > 0 && stdout_buf_len + ret < BUFSIZ)
44 {
45 memcpy(stdout_buf + stdout_buf_len, buf, (size_t)(ret + 1));
46 stdout_buf_len += ret;
47 }
48 else if (ret > 0) // No enough free buffer
49 {
50 ret = (BUFSIZ - stdout_buf_len - ret - 1);
51 }
52
53 return ret;
54 }
55
56 int iflush()
57 {
58 int flags;
59 fd_set write_fds;
60 struct timeval timeout;
61 int stdout_buf_offset = 0;
62 int loop = 1;
63 int ret = 0;
64
65 // Set STDOUT as non-blocking
66 flags = fcntl(STDOUT_FILENO, F_GETFL, 0);
67 fcntl(STDOUT_FILENO, F_SETFL, flags | O_NONBLOCK);
68
69 while (loop && !SYS_server_exit)
70 {
71 FD_ZERO(&write_fds);
72 FD_SET(STDOUT_FILENO, &write_fds);
73
74 timeout.tv_sec = 0;
75 timeout.tv_usec = 100 * 1000; // 0.1 second
76
77 ret = select(STDOUT_FILENO + 1, NULL, &write_fds, NULL, &timeout);
78
79 if (ret == 0) // timeout
80 {
81 continue;
82 }
83 else if (ret < 0)
84 {
85 if (errno != EINTR)
86 {
87 log_error("select() error (%d) !\n", errno);
88 loop = 0;
89 }
90 }
91 else if (FD_ISSET(STDOUT_FILENO, &write_fds))
92 {
93 ret = (int)write(STDOUT_FILENO, stdout_buf + stdout_buf_offset, (size_t)(stdout_buf_len - stdout_buf_offset));
94 if (ret < 0)
95 {
96 if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
97 {
98 log_error("write(STDOUT) error (%d)\n", errno);
99 loop = 0;
100 }
101 }
102 else if (ret == 0) // broken pipe
103 {
104 loop = 0;
105 }
106 else
107 {
108 stdout_buf_offset += ret;
109 if (stdout_buf_offset >= stdout_buf_len) // Flush buffer complete
110 {
111 ret = 0;
112 stdout_buf_len = 0;
113 loop = 0;
114 }
115 }
116 }
117 }
118
119 // Restore STDOUT flags
120 fcntl(STDOUT_FILENO, F_SETFL, flags);
121
122 return ret;
123 }
124
125 int igetch(int clear_buf)
126 {
127 // static input buffer
128 static unsigned char buf[LINE_BUFFER_LEN];
129 static ssize_t len = 0;
130 static int pos = 0;
131
132 fd_set readfds;
133 struct timeval timeout;
134
135 unsigned char tmp[LINE_BUFFER_LEN];
136 int ret;
137 int out = '\0';
138 int in_esc = 0;
139 int in_ascii = 0;
140 int in_control = 0;
141 int i = 0;
142 int flags;
143
144 if (clear_buf)
145 {
146 pos = 0;
147 len = 0;
148
149 return '\0';
150 }
151
152 while (!SYS_server_exit && pos >= len)
153 {
154 FD_ZERO(&readfds);
155 FD_SET(STDIN_FILENO, &readfds);
156
157 timeout.tv_sec = 0;
158 timeout.tv_usec = 100 * 1000; // 0.1 second
159
160 ret = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &timeout);
161
162 if (ret < 0)
163 {
164 if (errno != EINTR)
165 {
166 log_error("select() error (%d) !\n", errno);
167 return KEY_NULL;
168 }
169 continue;
170 }
171 else if (ret == 0)
172 {
173 return KEY_TIMEOUT;
174 }
175
176 if (FD_ISSET(STDIN_FILENO, &readfds))
177 {
178 flags = fcntl(STDIN_FILENO, F_GETFL, 0);
179 fcntl(socket_server, F_SETFL, flags | O_NONBLOCK);
180
181 len = read(STDIN_FILENO, buf, sizeof(buf));
182 if (len < 0)
183 {
184 if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
185 {
186 log_error("read(STDIN) error (%d)\n", errno);
187 }
188 }
189 else if (len == 0)
190 {
191 out = KEY_NULL; // broken pipe
192 }
193
194 pos = 0;
195
196 fcntl(STDIN_FILENO, F_SETFL, flags);
197
198 break;
199 }
200
201 // For debug
202 // for (j = 0; j < len; j++)
203 // log_std ("<--[%u]\n", (buf[j] + 256) % 256);
204 }
205
206 while (pos < len)
207 {
208 unsigned char c = buf[pos++];
209
210 if (c == KEY_CONTROL)
211 {
212 if (in_control == 0)
213 {
214 in_control = 1;
215 i = 0;
216 continue;
217 }
218 }
219
220 if (in_control)
221 {
222 tmp[i++] = c;
223 if (i >= 2)
224 {
225 out = (int)tmp[0] * 256 + tmp[1];
226 in_control = 0;
227 break;
228 }
229 continue;
230 }
231
232 if (c == ESC_KEY)
233 {
234 if (in_esc == 0)
235 {
236 in_esc = 1;
237 in_ascii = 1;
238 i = 0;
239 continue;
240 }
241 else
242 {
243 out = ESC_KEY;
244 in_esc = 0;
245 break;
246 }
247 }
248
249 in_esc = 0;
250
251 if (in_ascii)
252 {
253 tmp[i++] = c;
254 if (c == 'm')
255 {
256 in_ascii = 0;
257 continue;
258 }
259 if (i == 2 && c >= 'A' && c <= 'D')
260 {
261 in_ascii = 0;
262 switch (c)
263 {
264 case 'A':
265 out = KEY_UP;
266 break;
267 case 'B':
268 out = KEY_DOWN;
269 break;
270 case 'C':
271 out = KEY_RIGHT;
272 break;
273 case 'D':
274 out = KEY_LEFT;
275 break;
276 }
277 break;
278 }
279 if (i == 3 && tmp[0] == 91 && tmp[2] == 126)
280 {
281 in_ascii = 0;
282 switch (tmp[1])
283 {
284 case 49:
285 out = KEY_HOME;
286 break;
287 case 51:
288 out = KEY_DEL;
289 break;
290 case 52:
291 out = KEY_END;
292 break;
293 case 53:
294 out = KEY_PGUP;
295 break;
296 case 54:
297 out = KEY_PGDN;
298 break;
299 }
300 break;
301 }
302 continue;
303 }
304
305 out = ((int)c + 256) % 256;
306 break;
307 }
308
309 // for debug
310 // log_std ("-->[%u]\n", out);
311
312 return out;
313 }
314
315 int igetch_t(long int sec)
316 {
317 int ch;
318 time_t t_begin = time(0);
319
320 do
321 {
322 ch = igetch(0);
323 } while (!SYS_server_exit && ch == KEY_TIMEOUT && (time(0) - t_begin < sec));
324
325 return ch;
326 }

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