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

Annotation of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.30 - (hide 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 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    
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 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     return -1;
111     }
112    
113 sysadm 1.28 // Set STDOUT as non-blocking
114     flags = fcntl(STDOUT_FILENO, F_GETFL, 0);
115     fcntl(STDOUT_FILENO, F_SETFL, flags | O_NONBLOCK);
116    
117 sysadm 1.30 // Retry wait / flush for at most 3 times
118     retry = 3;
119     while (retry > 0 && !SYS_server_exit)
120 sysadm 1.28 {
121 sysadm 1.30 retry--;
122    
123 sysadm 1.29 nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); // 0.1 second
124 sysadm 1.28
125 sysadm 1.29 if (nfds < 0)
126 sysadm 1.28 {
127 sysadm 1.29 if (errno != EINTR)
128     {
129     log_error("epoll_wait() error (%d)\n", errno);
130     break;
131     }
132 sysadm 1.28 continue;
133     }
134 sysadm 1.29 else if (nfds == 0) // timeout
135 sysadm 1.28 {
136 sysadm 1.29 continue;
137 sysadm 1.28 }
138 sysadm 1.29
139     for (int i = 0; i < nfds; i++)
140 sysadm 1.28 {
141 sysadm 1.29 if (events[i].data.fd == STDOUT_FILENO)
142 sysadm 1.28 {
143 sysadm 1.30 while (stdout_buf_offset < stdout_buf_len && !SYS_server_exit) // write until complete or error
144 sysadm 1.28 {
145 sysadm 1.29 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 sysadm 1.30 retry = 0;
160 sysadm 1.29 break;
161     }
162     }
163     else if (ret == 0) // broken pipe
164     {
165 sysadm 1.30 retry = 0;
166 sysadm 1.29 break;
167     }
168     else
169     {
170     stdout_buf_offset += ret;
171 sysadm 1.30 if (stdout_buf_offset >= stdout_buf_len) // flush buffer completely
172 sysadm 1.29 {
173     ret = 0;
174 sysadm 1.30 stdout_buf_offset = 0;
175 sysadm 1.29 stdout_buf_len = 0;
176 sysadm 1.30 retry = 0;
177 sysadm 1.29 break;
178     }
179     continue;
180     }
181 sysadm 1.28 }
182     }
183     }
184     }
185 sysadm 1.6
186 sysadm 1.28 // Restore STDOUT flags
187     fcntl(STDOUT_FILENO, F_SETFL, flags);
188 sysadm 1.6
189 sysadm 1.28 return ret;
190 sysadm 1.1 }
191    
192 sysadm 1.17 int igetch(int clear_buf)
193 sysadm 1.1 {
194 sysadm 1.18 // static input buffer
195 sysadm 1.22 static unsigned char buf[LINE_BUFFER_LEN];
196 sysadm 1.19 static ssize_t len = 0;
197 sysadm 1.18 static int pos = 0;
198    
199 sysadm 1.29 struct epoll_event ev, events[MAX_EVENTS];
200     int nfds, epollfd;
201 sysadm 1.21
202 sysadm 1.22 unsigned char tmp[LINE_BUFFER_LEN];
203 sysadm 1.27 int out = '\0';
204 sysadm 1.18 int in_esc = 0;
205     int in_ascii = 0;
206     int in_control = 0;
207     int i = 0;
208 sysadm 1.26 int flags;
209 sysadm 1.1
210 sysadm 1.17 if (clear_buf)
211     {
212     pos = 0;
213     len = 0;
214    
215 sysadm 1.27 return '\0';
216 sysadm 1.17 }
217    
218 sysadm 1.29 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 sysadm 1.14 {
229 sysadm 1.29 log_error("epoll_ctl(STDIN_FILENO) error (%d)\n", errno);
230     return -1;
231     }
232 sysadm 1.9
233 sysadm 1.29 flags = fcntl(STDIN_FILENO, F_GETFL, 0);
234     fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
235 sysadm 1.9
236 sysadm 1.29 while (!SYS_server_exit && pos >= len)
237     {
238     nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); // 0.1 second
239 sysadm 1.9
240 sysadm 1.29 if (nfds < 0)
241 sysadm 1.14 {
242 sysadm 1.21 if (errno != EINTR)
243     {
244 sysadm 1.29 log_error("epoll_wait() error (%d)\n", errno);
245     fcntl(STDIN_FILENO, F_SETFL, flags);
246 sysadm 1.21 return KEY_NULL;
247     }
248     continue;
249 sysadm 1.14 }
250 sysadm 1.29 else if (nfds == 0)
251 sysadm 1.14 {
252 sysadm 1.29 fcntl(STDIN_FILENO, F_SETFL, flags);
253 sysadm 1.21 return KEY_TIMEOUT;
254 sysadm 1.14 }
255 sysadm 1.21
256 sysadm 1.29 for (int i = 0; i < nfds; i++)
257 sysadm 1.14 {
258 sysadm 1.29 if (events[i].data.fd == STDIN_FILENO)
259 sysadm 1.26 {
260 sysadm 1.30 while (!SYS_server_exit) // read until complete or error
261 sysadm 1.26 {
262 sysadm 1.29 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 sysadm 1.26 }
290     }
291 sysadm 1.14 }
292    
293     // For debug
294     // for (j = 0; j < len; j++)
295     // log_std ("<--[%u]\n", (buf[j] + 256) % 256);
296 sysadm 1.11 }
297 sysadm 1.14
298 sysadm 1.29 fcntl(STDIN_FILENO, F_SETFL, flags);
299    
300 sysadm 1.14 while (pos < len)
301 sysadm 1.11 {
302 sysadm 1.18 unsigned char c = buf[pos++];
303 sysadm 1.5
304 sysadm 1.14 if (c == KEY_CONTROL)
305     {
306     if (in_control == 0)
307     {
308     in_control = 1;
309     i = 0;
310     continue;
311     }
312     }
313 sysadm 1.1
314 sysadm 1.14 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 sysadm 1.6
326 sysadm 1.14 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 sysadm 1.3
343 sysadm 1.14 in_esc = 0;
344 sysadm 1.1
345 sysadm 1.14 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 sysadm 1.1
399 sysadm 1.14 out = ((int)c + 256) % 256;
400     break;
401 sysadm 1.1 }
402    
403 sysadm 1.14 // for debug
404     // log_std ("-->[%u]\n", out);
405 sysadm 1.1
406 sysadm 1.14 return out;
407 sysadm 1.1 }
408 sysadm 1.5
409 sysadm 1.14 int igetch_t(long int sec)
410 sysadm 1.9 {
411 sysadm 1.14 int ch;
412     time_t t_begin = time(0);
413 sysadm 1.10
414 sysadm 1.14 do
415     {
416 sysadm 1.17 ch = igetch(0);
417 sysadm 1.25 } while (!SYS_server_exit && ch == KEY_TIMEOUT && (time(0) - t_begin < sec));
418 sysadm 1.9
419 sysadm 1.14 return ch;
420 sysadm 1.9 }

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