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

Contents of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.34 - (show 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 /***************************************************************************
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 #include <sys/epoll.h>
30
31 static char stdout_buf[BUFSIZ];
32 static int stdout_buf_len = 0;
33 static int stdout_buf_offset = 0;
34
35 int prints(const char *format, ...)
36 {
37 char buf[BUFSIZ];
38 va_list args;
39 int ret;
40
41 va_start(args, format);
42 ret = vsnprintf(buf, sizeof(buf), format, args);
43 va_end(args);
44
45 if (ret > 0)
46 {
47 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 }
63
64 return ret;
65 }
66
67 int outc(char c)
68 {
69 int ret;
70
71 if (stdout_buf_len + 1 > BUFSIZ)
72 {
73 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 }
86
87 return ret;
88 }
89
90 int iflush()
91 {
92 int flags;
93 struct epoll_event ev, events[MAX_EVENTS];
94 int nfds, epollfd;
95 int retry;
96 int ret = 0;
97
98 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 if (close(epollfd) < 0)
111 {
112 log_error("close(epoll) error (%d)\n");
113 }
114 return -1;
115 }
116
117 // Set STDOUT as non-blocking
118 flags = fcntl(STDOUT_FILENO, F_GETFL, 0);
119 fcntl(STDOUT_FILENO, F_SETFL, flags | O_NONBLOCK);
120
121 // Retry wait / flush for at most 3 times
122 retry = 3;
123 while (retry > 0 && !SYS_server_exit)
124 {
125 retry--;
126
127 nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); // 0.1 second
128
129 if (nfds < 0)
130 {
131 if (errno != EINTR)
132 {
133 log_error("epoll_wait() error (%d)\n", errno);
134 break;
135 }
136 continue;
137 }
138 else if (nfds == 0) // timeout
139 {
140 continue;
141 }
142
143 for (int i = 0; i < nfds; i++)
144 {
145 if (events[i].data.fd == STDOUT_FILENO)
146 {
147 while (stdout_buf_offset < stdout_buf_len && !SYS_server_exit) // write until complete or error
148 {
149 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 retry = 0;
164 break;
165 }
166 }
167 else if (ret == 0) // broken pipe
168 {
169 retry = 0;
170 break;
171 }
172 else
173 {
174 stdout_buf_offset += ret;
175 if (stdout_buf_offset >= stdout_buf_len) // flush buffer completely
176 {
177 ret = 0;
178 stdout_buf_offset = 0;
179 stdout_buf_len = 0;
180 retry = 0;
181 break;
182 }
183 continue;
184 }
185 }
186 }
187 }
188 }
189
190 // Restore STDOUT flags
191 fcntl(STDOUT_FILENO, F_SETFL, flags);
192
193 if (close(epollfd) < 0)
194 {
195 log_error("close(epoll) error (%d)\n");
196 }
197
198 return ret;
199 }
200
201 int igetch(int timeout)
202 {
203 // static input buffer
204 static unsigned char buf[LINE_BUFFER_LEN];
205 static int len = 0;
206 static int pos = 0;
207
208 struct epoll_event ev, events[MAX_EVENTS];
209 int nfds, epollfd;
210 int ret;
211 int loop;
212
213 unsigned char tmp[LINE_BUFFER_LEN];
214 int out = KEY_NULL;
215 int in_esc = 0;
216 int in_ascii = 0;
217 int in_control = 0;
218 int i = 0;
219 int flags;
220
221 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 {
232 log_error("epoll_ctl(STDIN_FILENO) error (%d)\n", errno);
233
234 if (close(epollfd) < 0)
235 {
236 log_error("close(epoll) error (%d)\n");
237 }
238 return -1;
239 }
240
241 flags = fcntl(STDIN_FILENO, F_GETFL, 0);
242 fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
243
244 loop = 1;
245
246 while (loop && pos >= len && !SYS_server_exit)
247 {
248 len = 0;
249 pos = 0;
250
251 nfds = epoll_wait(epollfd, events, MAX_EVENTS, timeout);
252
253 if (nfds < 0)
254 {
255 if (errno != EINTR)
256 {
257 log_error("epoll_wait() error (%d)\n", errno);
258 break;
259 }
260 continue;
261 }
262 else if (nfds == 0) // timeout
263 {
264 out = KEY_TIMEOUT;
265 break;
266 }
267
268 for (int i = 0; i < nfds; i++)
269 {
270 if (events[i].data.fd == STDIN_FILENO)
271 {
272 while (len < sizeof(buf) && !SYS_server_exit) // read until complete or error
273 {
274 ret = (int)read(STDIN_FILENO, buf + len, sizeof(buf) - (size_t)len);
275 if (ret < 0)
276 {
277 if (errno == EAGAIN || errno == EWOULDBLOCK)
278 {
279 out = 0;
280 loop = 0;
281 break;
282 }
283 else if (errno == EINTR)
284 {
285 continue;
286 }
287 else
288 {
289 log_error("read(STDIN) error (%d)\n", errno);
290 loop = 0;
291 break;
292 }
293 }
294 else if (ret == 0) // broken pipe
295 {
296 loop = 0;
297 break;
298 }
299 else
300 {
301 len += ret;
302 continue;
303 }
304 }
305 }
306 }
307
308 // For debug
309 // for (int j = pos; j < len; j++)
310 // {
311 // log_std("Debug: <--[%u]\n", (buf[j] + 256) % 256);
312 // }
313 }
314
315 fcntl(STDIN_FILENO, F_SETFL, flags);
316
317 while (pos < len)
318 {
319 unsigned char c = buf[pos++];
320
321 if (c == KEY_CONTROL)
322 {
323 if (in_control == 0)
324 {
325 in_control = 1;
326 i = 0;
327 continue;
328 }
329 }
330
331 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
343 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
360 in_esc = 0;
361
362 if (in_ascii)
363 {
364 tmp[i++] = c;
365 if (i == 2 && (tmp[0] == 79 || tmp[0] == 91))
366 {
367 in_ascii = 0;
368 switch (tmp[1])
369 {
370 case 65:
371 out = KEY_UP;
372 break;
373 case 66:
374 out = KEY_DOWN;
375 break;
376 case 67:
377 out = KEY_RIGHT;
378 break;
379 case 68:
380 out = KEY_LEFT;
381 break;
382 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 }
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 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 }
671 }
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 }
727 continue;
728 }
729
730 out = ((int)c + 256) % 256;
731 break;
732 }
733
734 if (close(epollfd) < 0)
735 {
736 log_error("close(epoll) error (%d)\n");
737 }
738
739 // for debug
740 // if (out != KEY_TIMEOUT && out != KEY_NULL)
741 // {
742 // log_std ("Debug: -->[0x %x]\n", out);
743 // }
744
745 return out;
746 }
747
748 int igetch_t(int sec)
749 {
750 int ch;
751 time_t t_begin = time(0);
752
753 do
754 {
755 ch = igetch(100);
756 } while (!SYS_server_exit && ch == KEY_TIMEOUT && (time(0) - t_begin < sec));
757
758 return ch;
759 }
760
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