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

Annotation of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.34 - (hide annotations)
Tue May 20 12:07:06 2025 UTC (9 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.33: +4 -4 lines
Content type: text/x-csrc
Remove debug code

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 sysadm 1.33 // for (int j = pos; j < len; j++)
310     // {
311     // log_std("Debug: <--[%u]\n", (buf[j] + 256) % 256);
312     // }
313 sysadm 1.11 }
314 sysadm 1.14
315 sysadm 1.29 fcntl(STDIN_FILENO, F_SETFL, flags);
316    
317 sysadm 1.14 while (pos < len)
318 sysadm 1.11 {
319 sysadm 1.18 unsigned char c = buf[pos++];
320 sysadm 1.5
321 sysadm 1.14 if (c == KEY_CONTROL)
322     {
323     if (in_control == 0)
324     {
325     in_control = 1;
326     i = 0;
327     continue;
328     }
329     }
330 sysadm 1.1
331 sysadm 1.14 if (in_control)
332     {
333     tmp[i++] = c;
334     if (i >= 2)
335     {
336     out = (int)tmp[0] * 256 + tmp[1];
337     in_control = 0;
338     break;
339     }
340     continue;
341     }
342 sysadm 1.6
343 sysadm 1.14 if (c == ESC_KEY)
344     {
345     if (in_esc == 0)
346     {
347     in_esc = 1;
348     in_ascii = 1;
349     i = 0;
350     continue;
351     }
352     else
353     {
354     out = ESC_KEY;
355     in_esc = 0;
356     break;
357     }
358     }
359 sysadm 1.3
360 sysadm 1.14 in_esc = 0;
361 sysadm 1.1
362 sysadm 1.14 if (in_ascii)
363     {
364     tmp[i++] = c;
365 sysadm 1.33 if (i == 2 && (tmp[0] == 79 || tmp[0] == 91))
366 sysadm 1.14 {
367     in_ascii = 0;
368 sysadm 1.33 switch (tmp[1])
369 sysadm 1.14 {
370 sysadm 1.33 case 65:
371 sysadm 1.14 out = KEY_UP;
372     break;
373 sysadm 1.33 case 66:
374 sysadm 1.14 out = KEY_DOWN;
375     break;
376 sysadm 1.33 case 67:
377 sysadm 1.14 out = KEY_RIGHT;
378     break;
379 sysadm 1.33 case 68:
380 sysadm 1.14 out = KEY_LEFT;
381     break;
382 sysadm 1.33 default:
383     in_ascii = 1;
384     }
385     if (!in_ascii)
386     {
387     break;
388     }
389     }
390     if (i == 2 && tmp[0] == 91) // Fterm
391     {
392     in_ascii = 0;
393     switch (tmp[1])
394     {
395     case 86:
396     out = KEY_SHIFT_F1;
397     break;
398     case 90:
399     out = KEY_SHIFT_F2;
400     break;
401     case 97:
402     out = KEY_SHIFT_F3;
403     break;
404     case 98:
405     out = KEY_SHIFT_F4;
406     break;
407     case 99:
408     out = KEY_SHIFT_F5;
409     break;
410     case 100:
411     out = KEY_SHIFT_F6;
412     break;
413     case 101:
414     out = KEY_SHIFT_F7;
415     break;
416     case 102:
417     out = KEY_SHIFT_F8;
418     break;
419     case 103:
420     out = KEY_SHIFT_F9;
421     break;
422     case 104:
423     out = KEY_SHIFT_F10;
424     break;
425     case 107:
426     out = KEY_CTRL_F1;
427     break;
428     case 108:
429     out = KEY_CTRL_F2;
430     break;
431     case 109:
432     out = KEY_CTRL_F3;
433     break;
434     case 112:
435     out = KEY_CTRL_F6;
436     break;
437     case 113:
438     out = KEY_CTRL_F7;
439     break;
440     case 114:
441     out = KEY_CTRL_F8;
442     break;
443     case 115:
444     out = KEY_CTRL_F9;
445     break;
446     case 116:
447     out = KEY_CTRL_F10;
448     break;
449     default:
450     in_ascii = 1;
451     }
452     if (!in_ascii)
453     {
454     break;
455     }
456     }
457     if (i == 2 && tmp[0] == 79) // Xterm
458     {
459     in_ascii = 0;
460     switch (tmp[1])
461     {
462     case 80:
463     out = KEY_F1;
464     break;
465     case 81:
466     out = KEY_F2;
467     break;
468     case 82:
469     out = KEY_F3;
470     break;
471     case 83:
472     out = KEY_F4;
473     break;
474     default:
475     in_ascii = 1;
476     }
477     if (!in_ascii)
478     {
479     break;
480 sysadm 1.14 }
481     }
482     if (i == 3 && tmp[0] == 91 && tmp[2] == 126)
483     {
484     in_ascii = 0;
485     switch (tmp[1])
486     {
487     case 49:
488     out = KEY_HOME;
489     break;
490     case 51:
491     out = KEY_DEL;
492     break;
493     case 52:
494     out = KEY_END;
495     break;
496     case 53:
497     out = KEY_PGUP;
498     break;
499     case 54:
500     out = KEY_PGDN;
501     break;
502 sysadm 1.33 default:
503     in_ascii = 1;
504     }
505     if (!in_ascii)
506     {
507     break;
508     }
509     }
510     if (i == 4 && tmp[0] == 91 && tmp[1] == 49 && tmp[3] == 126) // Fterm
511     {
512     in_ascii = 0;
513     switch (tmp[2])
514     {
515     case 49:
516     out = KEY_F1;
517     break;
518     case 50:
519     out = KEY_F2;
520     break;
521     case 51:
522     out = KEY_F3;
523     break;
524     case 52:
525     out = KEY_F4;
526     break;
527     case 53:
528     out = KEY_F5;
529     break;
530     case 55:
531     out = KEY_F6;
532     break;
533     case 56:
534     out = KEY_F7;
535     break;
536     case 57:
537     out = KEY_F8;
538     break;
539     default:
540     in_ascii = 1;
541     }
542     if (!in_ascii)
543     {
544     break;
545     }
546     }
547     if (i == 4 && tmp[0] == 91 && tmp[1] == 50 && tmp[3] == 126) // Fterm
548     {
549     in_ascii = 0;
550     switch (tmp[2])
551     {
552     case 48:
553     out = KEY_F9;
554     break;
555     case 49:
556     out = KEY_F10;
557     break;
558     case 50:
559     out = KEY_F11; // Fterm
560     break;
561     case 51:
562     out = KEY_F11; // Xterm
563     break;
564     case 52:
565     out = KEY_F12; // Xterm
566     break;
567     default:
568     in_ascii = 1;
569     }
570     if (!in_ascii)
571     {
572     break;
573     }
574     }
575     if (i == 5 && tmp[0] == 91 && tmp[1] == 49 && tmp[2] == 59 && tmp[3] == 53) // Xterm
576     {
577     in_ascii = 0;
578     switch (tmp[4])
579     {
580     case 80:
581     out = KEY_CTRL_F1;
582     break;
583     case 81:
584     out = KEY_CTRL_F2;
585     break;
586     case 82:
587     out = KEY_CTRL_F3;
588     break;
589     default:
590     in_ascii = 1;
591     }
592     if (!in_ascii)
593     {
594     break;
595     }
596     }
597     if (i == 6 && tmp[0] == 91 && tmp[1] == 49 && tmp[3] == 59 && tmp[4] == 53 && tmp[5] == 126) // Xterm
598     {
599     in_ascii = 0;
600     switch (tmp[2])
601     {
602     case 53:
603     out = KEY_CTRL_F5;
604     break;
605     case 55:
606     out = KEY_CTRL_F6;
607     break;
608     case 56:
609     out = KEY_CTRL_F7;
610     break;
611     case 57:
612     out = KEY_CTRL_F8;
613     break;
614     default:
615     in_ascii = 1;
616     }
617     if (!in_ascii)
618     {
619     break;
620     }
621     }
622     if (i == 6 && tmp[0] == 91 && tmp[1] == 50 && tmp[3] == 59 && tmp[4] == 53 && tmp[5] == 126) // Xterm
623     {
624     in_ascii = 0;
625     switch (tmp[2])
626     {
627     case 48:
628     out = KEY_CTRL_F9;
629     break;
630     case 49:
631     out = KEY_CTRL_F10;
632     break;
633     case 51:
634     out = KEY_CTRL_F11;
635     break;
636     case 52:
637     out = KEY_CTRL_F12;
638     break;
639     default:
640     in_ascii = 1;
641     }
642     if (!in_ascii)
643     {
644     break;
645     }
646     }
647     if (i == 5 && tmp[0] == 91 && tmp[1] == 49 && tmp[2] == 59 && tmp[3] == 50) // Xterm
648     {
649     in_ascii = 0;
650     switch (tmp[4])
651     {
652     case 80:
653     out = KEY_SHIFT_F1;
654     break;
655     case 81:
656     out = KEY_SHIFT_F2;
657     break;
658     case 82:
659     out = KEY_SHIFT_F3;
660     break;
661     case 83:
662     out = KEY_SHIFT_F4;
663     break;
664     default:
665     in_ascii = 1;
666     }
667     if (!in_ascii)
668     {
669     break;
670 sysadm 1.14 }
671 sysadm 1.33 }
672     if (i == 6 && tmp[0] == 91 && tmp[1] == 49 && tmp[3] == 59 && tmp[4] == 50 && tmp[5] == 126) // Xterm
673     {
674     in_ascii = 0;
675     switch (tmp[2])
676     {
677     case 53:
678     out = KEY_SHIFT_F5;
679     break;
680     case 55:
681     out = KEY_SHIFT_F6;
682     break;
683     case 56:
684     out = KEY_SHIFT_F7;
685     break;
686     case 57:
687     out = KEY_SHIFT_F8;
688     break;
689     default:
690     in_ascii = 1;
691     }
692     if (!in_ascii)
693     {
694     break;
695     }
696     }
697     if (i == 6 && tmp[0] == 91 && tmp[1] == 50 && tmp[3] == 59 && tmp[4] == 50 && tmp[5] == 126) // Xterm
698     {
699     in_ascii = 0;
700     switch (tmp[2])
701     {
702     case 48:
703     out = KEY_SHIFT_F9;
704     break;
705     case 49:
706     out = KEY_SHIFT_F10;
707     break;
708     case 51:
709     out = KEY_SHIFT_F11;
710     break;
711     case 52:
712     out = KEY_SHIFT_F12;
713     break;
714     default:
715     in_ascii = 1;
716     }
717     if (!in_ascii)
718     {
719     break;
720     }
721     }
722    
723     if (c == 'm')
724     {
725     in_ascii = 0;
726 sysadm 1.14 }
727     continue;
728     }
729 sysadm 1.1
730 sysadm 1.14 out = ((int)c + 256) % 256;
731     break;
732 sysadm 1.1 }
733    
734 sysadm 1.31 if (close(epollfd) < 0)
735     {
736     log_error("close(epoll) error (%d)\n");
737     }
738    
739 sysadm 1.33 // for debug
740 sysadm 1.34 // if (out != KEY_TIMEOUT && out != KEY_NULL)
741     // {
742     // log_std ("Debug: -->[0x %x]\n", out);
743     // }
744 sysadm 1.33
745 sysadm 1.14 return out;
746 sysadm 1.1 }
747 sysadm 1.5
748 sysadm 1.31 int igetch_t(int sec)
749 sysadm 1.9 {
750 sysadm 1.14 int ch;
751     time_t t_begin = time(0);
752 sysadm 1.10
753 sysadm 1.14 do
754     {
755 sysadm 1.31 ch = igetch(100);
756 sysadm 1.25 } while (!SYS_server_exit && ch == KEY_TIMEOUT && (time(0) - t_begin < sec));
757 sysadm 1.9
758 sysadm 1.14 return ch;
759 sysadm 1.9 }
760 sysadm 1.31
761     void igetch_reset()
762     {
763     int ch;
764     do
765     {
766     ch = igetch(0);
767     } while (ch != KEY_NULL && ch != KEY_TIMEOUT);
768     }

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