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

Contents of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.57 - (show annotations)
Sun Oct 19 02:42:19 2025 UTC (4 months, 4 weeks ago) by sysadm
Branch: MAIN
Changes since 1.56: +8 -8 lines
Content type: text/x-csrc
Fix bug in igetch():
1) conv output buffer should be double size of input buffer
2) stop read if input buffer is full

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 "common.h"
18 #include "io.h"
19 #include "log.h"
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <time.h>
26 #include <unistd.h>
27 #include <sys/epoll.h>
28 #include <sys/ioctl.h>
29 #include <sys/select.h>
30 #include <libssh/callbacks.h>
31 #include <libssh/libssh.h>
32 #include <libssh/server.h>
33
34 char stdio_charset[32] = BBS_DEFAULT_CHARSET;
35
36 // static input / output buffer
37 static char stdin_buf[LINE_BUFFER_LEN];
38 static char stdout_buf[BUFSIZ];
39 static int stdin_buf_len = 0;
40 static int stdout_buf_len = 0;
41 static int stdin_buf_offset = 0;
42 static int stdout_buf_offset = 0;
43
44 static char stdin_conv[LINE_BUFFER_LEN * 2];
45 static char stdout_conv[BUFSIZ * 2];
46 static int stdin_conv_len = 0;
47 static int stdout_conv_len = 0;
48 static int stdin_conv_offset = 0;
49 static int stdout_conv_offset = 0;
50
51 static iconv_t stdin_cd = NULL;
52 static iconv_t stdout_cd = NULL;
53
54 int prints(const char *format, ...)
55 {
56 char buf[BUFSIZ];
57 va_list args;
58 int ret;
59
60 va_start(args, format);
61 ret = vsnprintf(buf, sizeof(buf), format, args);
62 va_end(args);
63
64 if (ret > 0)
65 {
66 if (stdout_buf_len + ret > BUFSIZ)
67 {
68 iflush();
69 }
70
71 if (stdout_buf_len + ret <= BUFSIZ)
72 {
73 memcpy(stdout_buf + stdout_buf_len, buf, (size_t)ret);
74 stdout_buf_len += ret;
75 }
76 else
77 {
78 errno = EAGAIN;
79 ret = (BUFSIZ - stdout_buf_len - ret);
80 log_error("Output buffer is full, additional %d is required\n", ret);
81 }
82 }
83
84 return ret;
85 }
86
87 int outc(char c)
88 {
89 int ret;
90
91 if (stdout_buf_len + 1 > BUFSIZ)
92 {
93 iflush();
94 }
95
96 if (stdout_buf_len + 1 <= BUFSIZ)
97 {
98 stdout_buf[stdout_buf_len] = c;
99 stdout_buf_len++;
100 }
101 else
102 {
103 errno = EAGAIN;
104 ret = -1;
105 }
106
107 return ret;
108 }
109
110 int iflush(void)
111 {
112 int flags;
113 struct epoll_event ev, events[MAX_EVENTS];
114 int nfds, epollfd;
115 int retry;
116 int ret = 0;
117
118 epollfd = epoll_create1(0);
119 if (epollfd < 0)
120 {
121 log_error("epoll_create1() error (%d)\n", errno);
122 return -1;
123 }
124
125 ev.events = EPOLLOUT;
126 ev.data.fd = STDOUT_FILENO;
127 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDOUT_FILENO, &ev) == -1)
128 {
129 log_error("epoll_ctl(STDOUT_FILENO) error (%d)\n", errno);
130 if (close(epollfd) < 0)
131 {
132 log_error("close(epoll) error (%d)\n");
133 }
134 return -1;
135 }
136
137 // Set STDOUT as non-blocking
138 flags = fcntl(STDOUT_FILENO, F_GETFL, 0);
139 fcntl(STDOUT_FILENO, F_SETFL, flags | O_NONBLOCK);
140
141 // Retry wait / flush for at most 3 times
142 retry = 3;
143 while (retry > 0 && !SYS_server_exit)
144 {
145 retry--;
146
147 nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); // 0.1 second
148
149 if (nfds < 0)
150 {
151 if (errno != EINTR)
152 {
153 log_error("epoll_wait() error (%d)\n", errno);
154 break;
155 }
156 continue;
157 }
158 else if (nfds == 0) // timeout
159 {
160 continue;
161 }
162
163 for (int i = 0; i < nfds; i++)
164 {
165 if (events[i].data.fd == STDOUT_FILENO)
166 {
167 if (stdout_buf_offset < stdout_buf_len)
168 {
169 ret = io_buf_conv(stdout_cd, stdout_buf, &stdout_buf_len, &stdout_buf_offset, stdout_conv, sizeof(stdout_conv), &stdout_conv_len);
170 if (ret < 0)
171 {
172 log_error("io_buf_conv(stdout, %d, %d, %d) error\n", stdout_buf_len, stdout_buf_offset, stdout_conv_len);
173 }
174 }
175
176 while (stdout_conv_offset < stdout_conv_len && !SYS_server_exit) // write until complete or error
177 {
178 if (SSH_v2)
179 {
180 ret = ssh_channel_write(SSH_channel, stdout_conv + stdout_conv_offset, (uint32_t)(stdout_conv_len - stdout_conv_offset));
181 if (ret == SSH_ERROR)
182 {
183 log_error("ssh_channel_write() error: %s\n", ssh_get_error(SSH_session));
184 retry = 0;
185 break;
186 }
187 }
188 else
189 {
190 ret = (int)write(STDOUT_FILENO, stdout_conv + stdout_conv_offset, (size_t)(stdout_conv_len - stdout_conv_offset));
191 }
192 if (ret < 0)
193 {
194 if (errno == EAGAIN || errno == EWOULDBLOCK)
195 {
196 break;
197 }
198 else if (errno == EINTR)
199 {
200 continue;
201 }
202 else
203 {
204 #ifdef _DEBUG
205 log_error("write(STDOUT) error (%d)\n", errno);
206 #endif
207 retry = 0;
208 break;
209 }
210 }
211 else if (ret == 0) // broken pipe
212 {
213 retry = 0;
214 break;
215 }
216 else
217 {
218 stdout_conv_offset += ret;
219 if (stdout_conv_offset >= stdout_conv_len) // flush buffer completely
220 {
221 ret = 0;
222 stdout_conv_offset = 0;
223 stdout_conv_len = 0;
224 retry = 0;
225 break;
226 }
227 continue;
228 }
229 }
230 }
231 }
232 }
233
234 // Restore STDOUT flags
235 fcntl(STDOUT_FILENO, F_SETFL, flags);
236
237 if (close(epollfd) < 0)
238 {
239 log_error("close(epoll) error (%d)\n");
240 }
241
242 return ret;
243 }
244
245 int igetch(int timeout)
246 {
247 struct epoll_event ev, events[MAX_EVENTS];
248 int nfds, epollfd;
249 int ret;
250 int loop;
251
252 unsigned char tmp[LINE_BUFFER_LEN];
253 int out = KEY_NULL;
254 int in_esc = 0;
255 int in_ascii = 0;
256 int in_control = 0;
257 int i = 0;
258 int flags;
259
260 if (stdin_conv_offset >= stdin_conv_len)
261 {
262 stdin_conv_len = 0;
263 stdin_conv_offset = 0;
264
265 epollfd = epoll_create1(0);
266 if (epollfd < 0)
267 {
268 log_error("epoll_create1() error (%d)\n", errno);
269 return -1;
270 }
271
272 ev.events = EPOLLIN;
273 ev.data.fd = STDIN_FILENO;
274 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) == -1)
275 {
276 log_error("epoll_ctl(STDIN_FILENO) error (%d)\n", errno);
277
278 if (close(epollfd) < 0)
279 {
280 log_error("close(epoll) error (%d)\n");
281 }
282 return -1;
283 }
284
285 flags = fcntl(STDIN_FILENO, F_GETFL, 0);
286 fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
287
288 for (loop = 1; loop && stdin_buf_len < sizeof(stdin_buf) && stdin_conv_offset >= stdin_conv_len && !SYS_server_exit;)
289 {
290 if (SSH_v2 && ssh_channel_is_closed(SSH_channel))
291 {
292 log_error("SSH channel is closed\n");
293 loop = 0;
294 break;
295 }
296
297 nfds = epoll_wait(epollfd, events, MAX_EVENTS, timeout);
298
299 if (nfds < 0)
300 {
301 if (errno != EINTR)
302 {
303 log_error("epoll_wait() error (%d)\n", errno);
304 break;
305 }
306 continue;
307 }
308 else if (nfds == 0) // timeout
309 {
310 out = KEY_TIMEOUT;
311 break;
312 }
313
314 for (int i = 0; i < nfds; i++)
315 {
316 if (events[i].data.fd == STDIN_FILENO)
317 {
318 while (stdin_buf_len < sizeof(stdin_buf) && !SYS_server_exit) // read until complete or error
319 {
320 if (SSH_v2)
321 {
322 ret = ssh_channel_read_nonblocking(SSH_channel, stdin_buf + stdin_buf_len, sizeof(stdin_buf) - (uint32_t)stdin_buf_len, 0);
323 if (ret == SSH_ERROR)
324 {
325 log_error("ssh_channel_read_nonblocking() error: %s\n", ssh_get_error(SSH_session));
326 loop = 0;
327 break;
328 }
329 else if (ret == SSH_EOF)
330 {
331 loop = 0;
332 break;
333 }
334 else if (ret == 0)
335 {
336 out = 0;
337 loop = 0;
338 break;
339 }
340 }
341 else
342 {
343 ret = (int)read(STDIN_FILENO, stdin_buf + stdin_buf_len, sizeof(stdin_buf) - (size_t)stdin_buf_len);
344 }
345 if (ret < 0)
346 {
347 if (errno == EAGAIN || errno == EWOULDBLOCK)
348 {
349 out = 0;
350 loop = 0;
351 break;
352 }
353 else if (errno == EINTR)
354 {
355 continue;
356 }
357 else
358 {
359 #ifdef _DEBUG
360 log_error("read(STDIN) error (%d)\n", errno);
361 #endif
362 loop = 0;
363 break;
364 }
365 }
366 else if (ret == 0) // broken pipe
367 {
368 loop = 0;
369 break;
370 }
371 else
372 {
373 stdin_buf_len += ret;
374 continue;
375 }
376 }
377 }
378 }
379
380 // For debug
381 #ifdef _DEBUG
382 for (int j = stdin_buf_offset; j < stdin_buf_len; j++)
383 {
384 log_error("Debug input: <--[%u]\n", (stdin_buf[j] + 256) % 256);
385 }
386 #endif
387 }
388
389 fcntl(STDIN_FILENO, F_SETFL, flags);
390
391 if (close(epollfd) < 0)
392 {
393 log_error("close(epoll) error (%d)\n");
394 }
395
396 if (stdin_buf_offset < stdin_buf_len)
397 {
398 ret = io_buf_conv(stdin_cd, stdin_buf, &stdin_buf_len, &stdin_buf_offset, stdin_conv, sizeof(stdin_conv), &stdin_conv_len);
399 if (ret < 0)
400 {
401 log_error("io_buf_conv(stdin, %d, %d, %d) error\n", stdin_buf_len, stdin_buf_offset, stdin_conv_len);
402 }
403
404 // For debug
405 #ifdef _DEBUG
406 for (int j = stdin_conv_offset; j < stdin_conv_len; j++)
407 {
408 log_error("Debug input_conv: <--[%u]\n", (stdin_conv[j] + 256) % 256);
409 }
410 #endif
411 }
412 }
413
414 while (stdin_conv_offset < stdin_conv_len)
415 {
416 unsigned char c = (unsigned char)stdin_conv[stdin_conv_offset++];
417
418 // Convert \r\n to \r
419 if (c == CR && stdin_conv_offset < stdin_conv_len && stdin_conv[stdin_conv_offset] == LF)
420 {
421 stdin_conv_offset++;
422 }
423
424 // Convert single \n to \r
425 if (c == LF)
426 {
427 c = CR;
428 }
429
430 if (c == KEY_CONTROL)
431 {
432 if (in_control == 0)
433 {
434 in_control = 1;
435 i = 0;
436 continue;
437 }
438 }
439
440 if (in_control)
441 {
442 tmp[i++] = c;
443 if (i >= 2)
444 {
445 out = (int)tmp[0] * 256 + tmp[1];
446 in_control = 0;
447 break;
448 }
449 continue;
450 }
451
452 if (c == KEY_ESC)
453 {
454 if (in_esc == 0)
455 {
456 in_esc = 1;
457 in_ascii = 1;
458 i = 0;
459 continue;
460 }
461 else
462 {
463 out = KEY_CSI;
464 in_esc = 0;
465 break;
466 }
467 }
468
469 in_esc = 0;
470
471 if (in_ascii)
472 {
473 tmp[i++] = c;
474 if (i == 2 && (tmp[0] == 79 || tmp[0] == 91))
475 {
476 in_ascii = 0;
477 switch (tmp[1])
478 {
479 case 65:
480 out = KEY_UP;
481 break;
482 case 66:
483 out = KEY_DOWN;
484 break;
485 case 67:
486 out = KEY_RIGHT;
487 break;
488 case 68:
489 out = KEY_LEFT;
490 break;
491 default:
492 in_ascii = 1;
493 }
494 if (!in_ascii)
495 {
496 break;
497 }
498 }
499 if (i == 2 && tmp[0] == 91) // Fterm
500 {
501 in_ascii = 0;
502 switch (tmp[1])
503 {
504 case 86:
505 out = KEY_SHIFT_F1;
506 break;
507 case 90:
508 out = KEY_SHIFT_F2;
509 break;
510 case 97:
511 out = KEY_SHIFT_F3;
512 break;
513 case 98:
514 out = KEY_SHIFT_F4;
515 break;
516 case 99:
517 out = KEY_SHIFT_F5;
518 break;
519 case 100:
520 out = KEY_SHIFT_F6;
521 break;
522 case 101:
523 out = KEY_SHIFT_F7;
524 break;
525 case 102:
526 out = KEY_SHIFT_F8;
527 break;
528 case 103:
529 out = KEY_SHIFT_F9;
530 break;
531 case 104:
532 out = KEY_SHIFT_F10;
533 break;
534 case 107:
535 out = KEY_CTRL_F1;
536 break;
537 case 108:
538 out = KEY_CTRL_F2;
539 break;
540 case 109:
541 out = KEY_CTRL_F3;
542 break;
543 case 112:
544 out = KEY_CTRL_F6;
545 break;
546 case 113:
547 out = KEY_CTRL_F7;
548 break;
549 case 114:
550 out = KEY_CTRL_F8;
551 break;
552 case 115:
553 out = KEY_CTRL_F9;
554 break;
555 case 116:
556 out = KEY_CTRL_F10;
557 break;
558 default:
559 in_ascii = 1;
560 }
561 if (!in_ascii)
562 {
563 break;
564 }
565 }
566 if (i == 2 && tmp[0] == 79) // Xterm
567 {
568 in_ascii = 0;
569 switch (tmp[1])
570 {
571 case 80:
572 out = KEY_F1;
573 break;
574 case 81:
575 out = KEY_F2;
576 break;
577 case 82:
578 out = KEY_F3;
579 break;
580 case 83:
581 out = KEY_F4;
582 break;
583 default:
584 in_ascii = 1;
585 }
586 if (!in_ascii)
587 {
588 break;
589 }
590 }
591 if (i == 3 && tmp[0] == 91 && tmp[2] == 126)
592 {
593 in_ascii = 0;
594 switch (tmp[1])
595 {
596 case 49:
597 out = KEY_HOME;
598 break;
599 case 50:
600 out = KEY_INS;
601 break;
602 case 51:
603 out = KEY_DEL;
604 break;
605 case 52:
606 out = KEY_END;
607 break;
608 case 53:
609 out = KEY_PGUP;
610 break;
611 case 54:
612 out = KEY_PGDN;
613 break;
614 default:
615 in_ascii = 1;
616 }
617 if (!in_ascii)
618 {
619 break;
620 }
621 }
622 if (i == 4 && tmp[0] == 91 && tmp[1] == 49 && tmp[3] == 126) // Fterm
623 {
624 in_ascii = 0;
625 switch (tmp[2])
626 {
627 case 49:
628 out = KEY_F1;
629 break;
630 case 50:
631 out = KEY_F2;
632 break;
633 case 51:
634 out = KEY_F3;
635 break;
636 case 52:
637 out = KEY_F4;
638 break;
639 case 53:
640 out = KEY_F5;
641 break;
642 case 55:
643 out = KEY_F6;
644 break;
645 case 56:
646 out = KEY_F7;
647 break;
648 case 57:
649 out = KEY_F8;
650 break;
651 default:
652 in_ascii = 1;
653 }
654 if (!in_ascii)
655 {
656 break;
657 }
658 }
659 if (i == 4 && tmp[0] == 91 && tmp[1] == 50 && tmp[3] == 126) // Fterm
660 {
661 in_ascii = 0;
662 switch (tmp[2])
663 {
664 case 48:
665 out = KEY_F9;
666 break;
667 case 49:
668 out = KEY_F10;
669 break;
670 case 50:
671 out = KEY_F11; // Fterm
672 break;
673 case 51:
674 out = KEY_F11; // Xterm
675 break;
676 case 52:
677 out = KEY_F12; // Xterm
678 break;
679 default:
680 in_ascii = 1;
681 }
682 if (!in_ascii)
683 {
684 break;
685 }
686 }
687 if (i == 5 && tmp[0] == 91 && tmp[1] == 49 && tmp[2] == 59 && tmp[3] == 53) // Xterm
688 {
689 in_ascii = 0;
690 switch (tmp[4])
691 {
692 case 65:
693 out = KEY_CTRL_UP;
694 break;
695 case 66:
696 out = KEY_CTRL_DOWN;
697 break;
698 case 67:
699 out = KEY_CTRL_RIGHT;
700 break;
701 case 68:
702 out = KEY_CTRL_LEFT;
703 break;
704 case 70:
705 out = KEY_CTRL_END;
706 break;
707 case 72:
708 out = KEY_CTRL_HOME;
709 break;
710 case 80:
711 out = KEY_CTRL_F1;
712 break;
713 case 81:
714 out = KEY_CTRL_F2;
715 break;
716 case 82:
717 out = KEY_CTRL_F3;
718 break;
719 default:
720 in_ascii = 1;
721 }
722 if (!in_ascii)
723 {
724 break;
725 }
726 }
727 if (i == 6 && tmp[0] == 91 && tmp[1] == 49 && tmp[3] == 59 && tmp[4] == 53 && tmp[5] == 126) // Xterm
728 {
729 in_ascii = 0;
730 switch (tmp[2])
731 {
732 case 53:
733 out = KEY_CTRL_F5;
734 break;
735 case 55:
736 out = KEY_CTRL_F6;
737 break;
738 case 56:
739 out = KEY_CTRL_F7;
740 break;
741 case 57:
742 out = KEY_CTRL_F8;
743 break;
744 default:
745 in_ascii = 1;
746 }
747 if (!in_ascii)
748 {
749 break;
750 }
751 }
752 if (i == 6 && tmp[0] == 91 && tmp[1] == 50 && tmp[3] == 59 && tmp[4] == 53 && tmp[5] == 126) // Xterm
753 {
754 in_ascii = 0;
755 switch (tmp[2])
756 {
757 case 48:
758 out = KEY_CTRL_F9;
759 break;
760 case 49:
761 out = KEY_CTRL_F10;
762 break;
763 case 51:
764 out = KEY_CTRL_F11;
765 break;
766 case 52:
767 out = KEY_CTRL_F12;
768 break;
769 default:
770 in_ascii = 1;
771 }
772 if (!in_ascii)
773 {
774 break;
775 }
776 }
777 if (i == 5 && tmp[0] == 91 && tmp[1] == 49 && tmp[2] == 59 && tmp[3] == 50) // Xterm
778 {
779 in_ascii = 0;
780 switch (tmp[4])
781 {
782 case 80:
783 out = KEY_SHIFT_F1;
784 break;
785 case 81:
786 out = KEY_SHIFT_F2;
787 break;
788 case 82:
789 out = KEY_SHIFT_F3;
790 break;
791 case 83:
792 out = KEY_SHIFT_F4;
793 break;
794 default:
795 in_ascii = 1;
796 }
797 if (!in_ascii)
798 {
799 break;
800 }
801 }
802 if (i == 6 && tmp[0] == 91 && tmp[1] == 49 && tmp[3] == 59 && tmp[4] == 50 && tmp[5] == 126) // Xterm
803 {
804 in_ascii = 0;
805 switch (tmp[2])
806 {
807 case 53:
808 out = KEY_SHIFT_F5;
809 break;
810 case 55:
811 out = KEY_SHIFT_F6;
812 break;
813 case 56:
814 out = KEY_SHIFT_F7;
815 break;
816 case 57:
817 out = KEY_SHIFT_F8;
818 break;
819 default:
820 in_ascii = 1;
821 }
822 if (!in_ascii)
823 {
824 break;
825 }
826 }
827 if (i == 6 && tmp[0] == 91 && tmp[1] == 50 && tmp[3] == 59 && tmp[4] == 50 && tmp[5] == 126) // Xterm
828 {
829 in_ascii = 0;
830 switch (tmp[2])
831 {
832 case 48:
833 out = KEY_SHIFT_F9;
834 break;
835 case 49:
836 out = KEY_SHIFT_F10;
837 break;
838 case 51:
839 out = KEY_SHIFT_F11;
840 break;
841 case 52:
842 out = KEY_SHIFT_F12;
843 break;
844 default:
845 in_ascii = 1;
846 }
847 if (!in_ascii)
848 {
849 break;
850 }
851 }
852
853 if (c == 'm')
854 {
855 in_ascii = 0;
856 }
857 continue;
858 }
859
860 out = ((int)c + 256) % 256;
861 break;
862 }
863
864 // For ESC key
865 if (out == 0 && in_esc)
866 {
867 out = KEY_ESC;
868 }
869
870 // for debug
871 #ifdef _DEBUG
872 if (out != KEY_TIMEOUT && out != KEY_NULL)
873 {
874 log_error("Debug: -->[0x %x]\n", out);
875 }
876 #endif
877
878 return out;
879 }
880
881 int igetch_t(int sec)
882 {
883 int ch;
884 time_t t_begin = time(NULL);
885
886 do
887 {
888 ch = igetch(100);
889 } while (!SYS_server_exit && ch == KEY_TIMEOUT && (time(NULL) - t_begin < sec));
890
891 return ch;
892 }
893
894 void igetch_reset()
895 {
896 int ch;
897 do
898 {
899 ch = igetch(100);
900 } while (ch != KEY_NULL && ch != KEY_TIMEOUT);
901 }
902
903 int io_buf_conv(iconv_t cd, char *p_buf, int *p_buf_len, int *p_buf_offset, char *p_conv, size_t conv_size, int *p_conv_len)
904 {
905 char *in_buf;
906 char *out_buf;
907 size_t in_bytes;
908 size_t out_bytes;
909 int ret;
910 int in_control = 0;
911 size_t i = 0;
912
913 if (cd == NULL || p_buf == NULL || p_buf_len == NULL || p_buf_offset == NULL || p_conv == NULL || p_conv_len == NULL)
914 {
915 log_error("NULL pointer error\n");
916 return -1;
917 }
918
919 in_buf = p_buf + *p_buf_offset;
920 in_bytes = (size_t)(*p_buf_len - *p_buf_offset);
921 out_buf = p_conv + *p_conv_len;
922 out_bytes = conv_size - (size_t)(*p_conv_len);
923
924 while (in_bytes > 0)
925 {
926 if ((unsigned char)(*in_buf) == KEY_CONTROL)
927 {
928 if (in_control == 0)
929 {
930 in_control = 1;
931 i = 0;
932 }
933 }
934
935 if (in_control)
936 {
937 if (out_bytes <= 0)
938 {
939 log_error("iconv(inbytes=%d, outbytes=%d) error: EILSEQ and E2BIG\n", in_bytes, out_bytes);
940 return -2;
941 }
942
943 *out_buf = *in_buf;
944 in_buf++;
945 out_buf++;
946 in_bytes--;
947 out_bytes--;
948
949 (*p_buf_offset)++;
950 *p_conv_len = (int)(conv_size - out_bytes);
951
952 i++;
953 if (i >= 2)
954 {
955 in_control = 0;
956 }
957 continue;
958 }
959
960 ret = (int)iconv(cd, &in_buf, &in_bytes, &out_buf, &out_bytes);
961 if (ret == -1)
962 {
963 if (errno == EINVAL) // Incomplete
964 {
965 #ifdef _DEBUG
966 log_error("iconv(inbytes=%d, outbytes=%d) error: EINVAL, in_buf[0]=%d\n", in_bytes, out_bytes, in_buf[0]);
967 #endif
968 if (p_buf != in_buf)
969 {
970 *p_buf_len = (int)(p_buf + *p_buf_len - in_buf);
971 *p_buf_offset = 0;
972 *p_conv_len = (int)(conv_size - out_bytes);
973 memmove(p_buf, in_buf, (size_t)(*p_buf_len));
974 }
975
976 break;
977 }
978 else if (errno == E2BIG)
979 {
980 log_error("iconv(inbytes=%d, outbytes=%d) error: E2BIG\n", in_bytes, out_bytes);
981 return -1;
982 }
983 else if (errno == EILSEQ)
984 {
985 if (in_bytes > out_bytes || out_bytes <= 0)
986 {
987 log_error("iconv(inbytes=%d, outbytes=%d) error: EILSEQ and E2BIG\n", in_bytes, out_bytes);
988 return -2;
989 }
990
991 *out_buf = *in_buf;
992 in_buf++;
993 out_buf++;
994 in_bytes--;
995 out_bytes--;
996
997 continue;
998 }
999 }
1000 else
1001 {
1002 *p_buf_len = 0;
1003 *p_buf_offset = 0;
1004 *p_conv_len = (int)(conv_size - out_bytes);
1005
1006 break;
1007 }
1008 }
1009
1010 return 0;
1011 }
1012
1013 int io_conv_init(const char *charset)
1014 {
1015 if (charset == NULL)
1016 {
1017 log_error("NULL pointer error\n");
1018 return -1;
1019 }
1020
1021 io_conv_cleanup();
1022
1023 snprintf(stdio_charset, sizeof(stdio_charset), "%s//TRANSLIT", charset);
1024
1025 stdin_cd = iconv_open(BBS_DEFAULT_CHARSET, stdio_charset);
1026 if (stdin_cd == (iconv_t)(-1))
1027 {
1028 log_error("iconv_open(%s->%s) error: %d\n", stdio_charset, BBS_DEFAULT_CHARSET, errno);
1029 return -2;
1030 }
1031 stdout_cd = iconv_open(stdio_charset, BBS_DEFAULT_CHARSET);
1032 if (stdout_cd == (iconv_t)(-1))
1033 {
1034 log_error("iconv_open(%s->%s) error: %d\n", BBS_DEFAULT_CHARSET, stdio_charset, errno);
1035 iconv_close(stdin_cd);
1036 return -2;
1037 }
1038
1039 return 0;
1040 }
1041
1042 int io_conv_cleanup(void)
1043 {
1044 if (stdin_cd != NULL)
1045 {
1046 iconv_close(stdin_cd);
1047 stdin_cd = NULL;
1048 }
1049 if (stdout_cd != NULL)
1050 {
1051 iconv_close(stdout_cd);
1052 stdout_cd = NULL;
1053 }
1054
1055 return 0;
1056 }

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