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

Annotation of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.32 - (hide annotations)
Mon May 19 13:03:14 2025 UTC (9 months, 4 weeks ago) by sysadm
Branch: MAIN
Changes since 1.31: +1 -0 lines
Content type: text/x-csrc
Fix bug

1 sysadm 1.1 /***************************************************************************
2 sysadm 1.14 io.c - description
3     -------------------
4 sysadm 1.20 Copyright : (C) 2004-2025 by Leaflet
5     Email : leaflet@leafok.com
6 sysadm 1.1 ***************************************************************************/
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 sysadm 1.20 * the Free Software Foundation; either version 3 of the License, or *
13 sysadm 1.1 * (at your option) any later version. *
14     * *
15     ***************************************************************************/
16    
17     #include "io.h"
18 sysadm 1.16 #include "log.h"
19 sysadm 1.1 #include "common.h"
20 sysadm 1.22 #include <errno.h>
21 sysadm 1.1 #include <stdio.h>
22     #include <stdarg.h>
23 sysadm 1.28 #include <string.h>
24 sysadm 1.9 #include <time.h>
25     #include <fcntl.h>
26     #include <unistd.h>
27 sysadm 1.22 #include <sys/select.h>
28 sysadm 1.5 #include <sys/ioctl.h>
29 sysadm 1.29 #include <sys/epoll.h>
30 sysadm 1.1
31 sysadm 1.28 static char stdout_buf[BUFSIZ];
32     static int stdout_buf_len = 0;
33 sysadm 1.30 static int stdout_buf_offset = 0;
34 sysadm 1.1
35 sysadm 1.14 int prints(const char *format, ...)
36 sysadm 1.1 {
37 sysadm 1.28 char buf[BUFSIZ];
38 sysadm 1.14 va_list args;
39 sysadm 1.28 int ret;
40 sysadm 1.1
41 sysadm 1.14 va_start(args, format);
42 sysadm 1.28 ret = vsnprintf(buf, sizeof(buf), format, args);
43 sysadm 1.14 va_end(args);
44 sysadm 1.1
45 sysadm 1.30 if (ret > 0)
46 sysadm 1.28 {
47 sysadm 1.30 if (stdout_buf_len + ret > BUFSIZ)
48     {
49     iflush();
50     }
51 sysadm 1.31
52 sysadm 1.30 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 sysadm 1.28 }
63 sysadm 1.30
64     return ret;
65     }
66    
67     int outc(char c)
68     {
69     int ret;
70    
71     if (stdout_buf_len + 1 > BUFSIZ)
72 sysadm 1.28 {
73 sysadm 1.30 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 sysadm 1.28 }
86    
87     return ret;
88 sysadm 1.1 }
89    
90 sysadm 1.14 int iflush()
91 sysadm 1.1 {
92 sysadm 1.28 int flags;
93 sysadm 1.29 struct epoll_event ev, events[MAX_EVENTS];
94     int nfds, epollfd;
95 sysadm 1.30 int retry;
96 sysadm 1.28 int ret = 0;
97    
98 sysadm 1.29 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 sysadm 1.31 if (close(epollfd) < 0)
111     {
112     log_error("close(epoll) error (%d)\n");
113     }
114 sysadm 1.29 return -1;
115     }
116    
117 sysadm 1.28 // Set STDOUT as non-blocking
118     flags = fcntl(STDOUT_FILENO, F_GETFL, 0);
119     fcntl(STDOUT_FILENO, F_SETFL, flags | O_NONBLOCK);
120    
121 sysadm 1.30 // Retry wait / flush for at most 3 times
122     retry = 3;
123     while (retry > 0 && !SYS_server_exit)
124 sysadm 1.28 {
125 sysadm 1.30 retry--;
126    
127 sysadm 1.29 nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); // 0.1 second
128 sysadm 1.28
129 sysadm 1.29 if (nfds < 0)
130 sysadm 1.28 {
131 sysadm 1.29 if (errno != EINTR)
132     {
133     log_error("epoll_wait() error (%d)\n", errno);
134     break;
135     }
136 sysadm 1.28 continue;
137     }
138 sysadm 1.29 else if (nfds == 0) // timeout
139 sysadm 1.28 {
140 sysadm 1.29 continue;
141 sysadm 1.28 }
142 sysadm 1.29
143     for (int i = 0; i < nfds; i++)
144 sysadm 1.28 {
145 sysadm 1.29 if (events[i].data.fd == STDOUT_FILENO)
146 sysadm 1.28 {
147 sysadm 1.30 while (stdout_buf_offset < stdout_buf_len && !SYS_server_exit) // write until complete or error
148 sysadm 1.28 {
149 sysadm 1.29 ret = (int)write(STDOUT_FILENO, stdout_buf + stdout_buf_offset, (size_t)(stdout_buf_len - stdout_buf_offset));
150     if (ret < 0)
151     {
152     if (errno == EAGAIN || errno == EWOULDBLOCK)
153     {
154     break;
155     }
156     else if (errno == EINTR)
157     {
158     continue;
159     }
160     else
161     {
162     log_error("write(STDOUT) error (%d)\n", errno);
163 sysadm 1.30 retry = 0;
164 sysadm 1.29 break;
165     }
166     }
167     else if (ret == 0) // broken pipe
168     {
169 sysadm 1.30 retry = 0;
170 sysadm 1.29 break;
171     }
172     else
173     {
174     stdout_buf_offset += ret;
175 sysadm 1.30 if (stdout_buf_offset >= stdout_buf_len) // flush buffer completely
176 sysadm 1.29 {
177     ret = 0;
178 sysadm 1.30 stdout_buf_offset = 0;
179 sysadm 1.29 stdout_buf_len = 0;
180 sysadm 1.30 retry = 0;
181 sysadm 1.29 break;
182     }
183     continue;
184     }
185 sysadm 1.28 }
186     }
187     }
188     }
189 sysadm 1.6
190 sysadm 1.28 // Restore STDOUT flags
191     fcntl(STDOUT_FILENO, F_SETFL, flags);
192 sysadm 1.6
193 sysadm 1.31 if (close(epollfd) < 0)
194     {
195     log_error("close(epoll) error (%d)\n");
196     }
197    
198 sysadm 1.28 return ret;
199 sysadm 1.1 }
200    
201 sysadm 1.31 int igetch(int timeout)
202 sysadm 1.1 {
203 sysadm 1.18 // static input buffer
204 sysadm 1.22 static unsigned char buf[LINE_BUFFER_LEN];
205 sysadm 1.31 static int len = 0;
206 sysadm 1.18 static int pos = 0;
207    
208 sysadm 1.29 struct epoll_event ev, events[MAX_EVENTS];
209     int nfds, epollfd;
210 sysadm 1.31 int ret;
211     int loop;
212 sysadm 1.21
213 sysadm 1.22 unsigned char tmp[LINE_BUFFER_LEN];
214 sysadm 1.31 int out = KEY_NULL;
215 sysadm 1.18 int in_esc = 0;
216     int in_ascii = 0;
217     int in_control = 0;
218     int i = 0;
219 sysadm 1.26 int flags;
220 sysadm 1.1
221 sysadm 1.29 epollfd = epoll_create1(0);
222     if (epollfd < 0)
223     {
224     log_error("epoll_create1() error (%d)\n", errno);
225     return -1;
226     }
227    
228     ev.events = EPOLLIN;
229     ev.data.fd = STDIN_FILENO;
230     if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) == -1)
231 sysadm 1.14 {
232 sysadm 1.29 log_error("epoll_ctl(STDIN_FILENO) error (%d)\n", errno);
233 sysadm 1.31
234     if (close(epollfd) < 0)
235     {
236     log_error("close(epoll) error (%d)\n");
237     }
238 sysadm 1.29 return -1;
239     }
240 sysadm 1.9
241 sysadm 1.29 flags = fcntl(STDIN_FILENO, F_GETFL, 0);
242     fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
243 sysadm 1.9
244 sysadm 1.31 loop = 1;
245    
246     while (loop && pos >= len && !SYS_server_exit)
247 sysadm 1.29 {
248 sysadm 1.31 len = 0;
249     pos = 0;
250    
251     nfds = epoll_wait(epollfd, events, MAX_EVENTS, timeout);
252 sysadm 1.9
253 sysadm 1.29 if (nfds < 0)
254 sysadm 1.14 {
255 sysadm 1.21 if (errno != EINTR)
256     {
257 sysadm 1.29 log_error("epoll_wait() error (%d)\n", errno);
258 sysadm 1.31 break;
259 sysadm 1.21 }
260     continue;
261 sysadm 1.14 }
262 sysadm 1.31 else if (nfds == 0) // timeout
263 sysadm 1.14 {
264 sysadm 1.31 out = KEY_TIMEOUT;
265     break;
266 sysadm 1.14 }
267 sysadm 1.21
268 sysadm 1.29 for (int i = 0; i < nfds; i++)
269 sysadm 1.14 {
270 sysadm 1.29 if (events[i].data.fd == STDIN_FILENO)
271 sysadm 1.26 {
272 sysadm 1.31 while (len < sizeof(buf) && !SYS_server_exit) // read until complete or error
273 sysadm 1.26 {
274 sysadm 1.31 ret = (int)read(STDIN_FILENO, buf + len, sizeof(buf) - (size_t)len);
275     if (ret < 0)
276 sysadm 1.29 {
277     if (errno == EAGAIN || errno == EWOULDBLOCK)
278     {
279 sysadm 1.32 out = 0;
280 sysadm 1.31 loop = 0;
281     break;
282 sysadm 1.29 }
283     else if (errno == EINTR)
284     {
285     continue;
286     }
287     else
288     {
289     log_error("read(STDIN) error (%d)\n", errno);
290 sysadm 1.31 loop = 0;
291     break;
292 sysadm 1.29 }
293     }
294 sysadm 1.31 else if (ret == 0) // broken pipe
295 sysadm 1.29 {
296 sysadm 1.31 loop = 0;
297     break;
298     }
299     else
300     {
301     len += ret;
302     continue;
303 sysadm 1.29 }
304 sysadm 1.26 }
305     }
306 sysadm 1.14 }
307    
308     // For debug
309     // for (j = 0; j < len; j++)
310     // log_std ("<--[%u]\n", (buf[j] + 256) % 256);
311 sysadm 1.11 }
312 sysadm 1.14
313 sysadm 1.29 fcntl(STDIN_FILENO, F_SETFL, flags);
314    
315 sysadm 1.14 while (pos < len)
316 sysadm 1.11 {
317 sysadm 1.18 unsigned char c = buf[pos++];
318 sysadm 1.5
319 sysadm 1.14 if (c == KEY_CONTROL)
320     {
321     if (in_control == 0)
322     {
323     in_control = 1;
324     i = 0;
325     continue;
326     }
327     }
328 sysadm 1.1
329 sysadm 1.14 if (in_control)
330     {
331     tmp[i++] = c;
332     if (i >= 2)
333     {
334     out = (int)tmp[0] * 256 + tmp[1];
335     in_control = 0;
336     break;
337     }
338     continue;
339     }
340 sysadm 1.6
341 sysadm 1.14 if (c == ESC_KEY)
342     {
343     if (in_esc == 0)
344     {
345     in_esc = 1;
346     in_ascii = 1;
347     i = 0;
348     continue;
349     }
350     else
351     {
352     out = ESC_KEY;
353     in_esc = 0;
354     break;
355     }
356     }
357 sysadm 1.3
358 sysadm 1.14 in_esc = 0;
359 sysadm 1.1
360 sysadm 1.14 if (in_ascii)
361     {
362     tmp[i++] = c;
363     if (c == 'm')
364     {
365     in_ascii = 0;
366     continue;
367     }
368     if (i == 2 && c >= 'A' && c <= 'D')
369     {
370     in_ascii = 0;
371     switch (c)
372     {
373     case 'A':
374     out = KEY_UP;
375     break;
376     case 'B':
377     out = KEY_DOWN;
378     break;
379     case 'C':
380     out = KEY_RIGHT;
381     break;
382     case 'D':
383     out = KEY_LEFT;
384     break;
385     }
386     break;
387     }
388     if (i == 3 && tmp[0] == 91 && tmp[2] == 126)
389     {
390     in_ascii = 0;
391     switch (tmp[1])
392     {
393     case 49:
394     out = KEY_HOME;
395     break;
396     case 51:
397     out = KEY_DEL;
398     break;
399     case 52:
400     out = KEY_END;
401     break;
402     case 53:
403     out = KEY_PGUP;
404     break;
405     case 54:
406     out = KEY_PGDN;
407     break;
408     }
409     break;
410     }
411     continue;
412     }
413 sysadm 1.1
414 sysadm 1.14 out = ((int)c + 256) % 256;
415     break;
416 sysadm 1.1 }
417    
418 sysadm 1.14 // for debug
419     // log_std ("-->[%u]\n", out);
420 sysadm 1.1
421 sysadm 1.31 if (close(epollfd) < 0)
422     {
423     log_error("close(epoll) error (%d)\n");
424     }
425    
426 sysadm 1.14 return out;
427 sysadm 1.1 }
428 sysadm 1.5
429 sysadm 1.31 int igetch_t(int sec)
430 sysadm 1.9 {
431 sysadm 1.14 int ch;
432     time_t t_begin = time(0);
433 sysadm 1.10
434 sysadm 1.14 do
435     {
436 sysadm 1.31 ch = igetch(100);
437 sysadm 1.25 } while (!SYS_server_exit && ch == KEY_TIMEOUT && (time(0) - t_begin < sec));
438 sysadm 1.9
439 sysadm 1.14 return ch;
440 sysadm 1.9 }
441 sysadm 1.31
442     void igetch_reset()
443     {
444     int ch;
445     do
446     {
447     ch = igetch(0);
448     } while (ch != KEY_NULL && ch != KEY_TIMEOUT);
449     }

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