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

Annotation of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.31 - (hide annotations)
Tue May 13 07:28:51 2025 UTC (10 months ago) by sysadm
Branch: MAIN
Changes since 1.30: +62 -34 lines
Content type: text/x-csrc
Refine igetch/igetch_t

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.31 loop = 0;
280     break;
281 sysadm 1.29 }
282     else if (errno == EINTR)
283     {
284     continue;
285     }
286     else
287     {
288     log_error("read(STDIN) error (%d)\n", errno);
289 sysadm 1.31 loop = 0;
290     break;
291 sysadm 1.29 }
292     }
293 sysadm 1.31 else if (ret == 0) // broken pipe
294 sysadm 1.29 {
295 sysadm 1.31 loop = 0;
296     break;
297     }
298     else
299     {
300     len += ret;
301     continue;
302 sysadm 1.29 }
303 sysadm 1.26 }
304     }
305 sysadm 1.14 }
306    
307     // For debug
308     // for (j = 0; j < len; j++)
309     // log_std ("<--[%u]\n", (buf[j] + 256) % 256);
310 sysadm 1.11 }
311 sysadm 1.14
312 sysadm 1.29 fcntl(STDIN_FILENO, F_SETFL, flags);
313    
314 sysadm 1.14 while (pos < len)
315 sysadm 1.11 {
316 sysadm 1.18 unsigned char c = buf[pos++];
317 sysadm 1.5
318 sysadm 1.14 if (c == KEY_CONTROL)
319     {
320     if (in_control == 0)
321     {
322     in_control = 1;
323     i = 0;
324     continue;
325     }
326     }
327 sysadm 1.1
328 sysadm 1.14 if (in_control)
329     {
330     tmp[i++] = c;
331     if (i >= 2)
332     {
333     out = (int)tmp[0] * 256 + tmp[1];
334     in_control = 0;
335     break;
336     }
337     continue;
338     }
339 sysadm 1.6
340 sysadm 1.14 if (c == ESC_KEY)
341     {
342     if (in_esc == 0)
343     {
344     in_esc = 1;
345     in_ascii = 1;
346     i = 0;
347     continue;
348     }
349     else
350     {
351     out = ESC_KEY;
352     in_esc = 0;
353     break;
354     }
355     }
356 sysadm 1.3
357 sysadm 1.14 in_esc = 0;
358 sysadm 1.1
359 sysadm 1.14 if (in_ascii)
360     {
361     tmp[i++] = c;
362     if (c == 'm')
363     {
364     in_ascii = 0;
365     continue;
366     }
367     if (i == 2 && c >= 'A' && c <= 'D')
368     {
369     in_ascii = 0;
370     switch (c)
371     {
372     case 'A':
373     out = KEY_UP;
374     break;
375     case 'B':
376     out = KEY_DOWN;
377     break;
378     case 'C':
379     out = KEY_RIGHT;
380     break;
381     case 'D':
382     out = KEY_LEFT;
383     break;
384     }
385     break;
386     }
387     if (i == 3 && tmp[0] == 91 && tmp[2] == 126)
388     {
389     in_ascii = 0;
390     switch (tmp[1])
391     {
392     case 49:
393     out = KEY_HOME;
394     break;
395     case 51:
396     out = KEY_DEL;
397     break;
398     case 52:
399     out = KEY_END;
400     break;
401     case 53:
402     out = KEY_PGUP;
403     break;
404     case 54:
405     out = KEY_PGDN;
406     break;
407     }
408     break;
409     }
410     continue;
411     }
412 sysadm 1.1
413 sysadm 1.14 out = ((int)c + 256) % 256;
414     break;
415 sysadm 1.1 }
416    
417 sysadm 1.14 // for debug
418     // log_std ("-->[%u]\n", out);
419 sysadm 1.1
420 sysadm 1.31 if (close(epollfd) < 0)
421     {
422     log_error("close(epoll) error (%d)\n");
423     }
424    
425 sysadm 1.14 return out;
426 sysadm 1.1 }
427 sysadm 1.5
428 sysadm 1.31 int igetch_t(int sec)
429 sysadm 1.9 {
430 sysadm 1.14 int ch;
431     time_t t_begin = time(0);
432 sysadm 1.10
433 sysadm 1.14 do
434     {
435 sysadm 1.31 ch = igetch(100);
436 sysadm 1.25 } while (!SYS_server_exit && ch == KEY_TIMEOUT && (time(0) - t_begin < sec));
437 sysadm 1.9
438 sysadm 1.14 return ch;
439 sysadm 1.9 }
440 sysadm 1.31
441     void igetch_reset()
442     {
443     int ch;
444     do
445     {
446     ch = igetch(0);
447     } while (ch != KEY_NULL && ch != KEY_TIMEOUT);
448     }

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