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

Contents of /lbbs/src/screen.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.129 - (show annotations)
Tue Nov 11 00:28:05 2025 UTC (4 months ago) by sysadm
Branch: MAIN
Changes since 1.128: +4 -0 lines
Content type: text/x-csrc
Use config.h

1 /* SPDX-License-Identifier: GPL-3.0-or-later */
2 /*
3 * screen
4 * - advanced telnet-based user interactive input / output features
5 *
6 * Copyright (C) 2004-2025 Leaflet <leaflet@leafok.com>
7 */
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 #include "bbs.h"
14 #include "common.h"
15 #include "editor.h"
16 #include "file_loader.h"
17 #include "io.h"
18 #include "log.h"
19 #include "login.h"
20 #include "screen.h"
21 #include "str_process.h"
22 #include <ctype.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <wchar.h>
29 #include <sys/param.h>
30 #include <sys/stat.h>
31 #include <sys/shm.h>
32 #include <sys/types.h>
33
34 const char CTRL_SEQ_CLR_LINE[] = "\033[K";
35
36 static const int ACTIVE_BOARD_HEIGHT = 8;
37
38 static const int STR_TOP_LEFT_MAX_LEN = 80;
39 static const int STR_TOP_MIDDLE_MAX_LEN = 40;
40 static const int STR_TOP_RIGHT_MAX_LEN = 80;
41
42 static size_t get_time_str(char *s, size_t len)
43 {
44 time_t curtime;
45 struct tm local_tm;
46
47 time(&curtime);
48 localtime_r(&curtime, &local_tm);
49 size_t j = strftime(s, len, "%m/%d %H:%M %Z", &local_tm);
50
51 return j;
52 }
53
54 void moveto(int row, int col)
55 {
56 if (row >= 0)
57 {
58 prints("\033[%d;%dH", row, col);
59 }
60 else
61 {
62 prints("\r");
63 }
64 }
65
66 void clrtoeol()
67 {
68 prints(CTRL_SEQ_CLR_LINE);
69 }
70
71 void clrline(int line_begin, int line_end)
72 {
73 int i;
74
75 for (i = line_begin; i <= line_end; i++)
76 {
77 moveto(i, 0);
78 prints(CTRL_SEQ_CLR_LINE);
79 }
80 }
81
82 void clrtobot(int line_begin)
83 {
84 moveto(line_begin, 0);
85 prints("\033[J");
86 moveto(line_begin, 0);
87 }
88
89 void clearscr()
90 {
91 prints("\033[2J");
92 moveto(0, 0);
93 }
94
95 inline int press_any_key()
96 {
97 return press_any_key_ex(" \033[1;33m按任意键继续...\033[m", 60);
98 }
99
100 int press_any_key_ex(const char *msg, int sec)
101 {
102 int ch = 0;
103 int duration = 0;
104 time_t t_begin = time(NULL);
105
106 moveto(SCREEN_ROWS, 0);
107 clrtoeol();
108
109 prints(msg);
110 iflush();
111
112 igetch_reset();
113
114 do
115 {
116 ch = igetch_t(sec - duration);
117 duration = (int)(time(NULL) - t_begin);
118 } while (!SYS_server_exit && ch == 0 && duration < 60);
119
120 return ch;
121 }
122
123 void set_input_echo(int echo)
124 {
125 if (echo)
126 {
127 outc('\x83'); // ASCII code 131
128 }
129 else
130 {
131 // outc ('\x85'); // ASCII code 133
132 prints("\xff\xfb\x01\xff\xfb\x03");
133 }
134 iflush();
135 }
136
137 static int _str_input(char *buffer, int buf_size, int max_display_len, enum io_echo_t echo_mode)
138 {
139 int ch;
140 int offset = 0;
141 int eol;
142 int display_len;
143 char input_str[5];
144 int str_len = 0;
145 wchar_t wcs[2];
146 char c;
147
148 buffer[buf_size - 1] = '\0';
149 offset = split_line(buffer, max_display_len, &eol, &display_len, 0);
150
151 igetch_reset();
152
153 while (!SYS_server_exit)
154 {
155 ch = igetch_t(MIN(BBS_max_user_idle_time, 60));
156
157 if (ch == CR)
158 {
159 break;
160 }
161 else if (ch == KEY_TIMEOUT || ch == KEY_NULL) // timeout or broken pipe
162 {
163 return -1;
164 }
165 else if (ch == LF || ch == '\0')
166 {
167 continue;
168 }
169 else if (ch == BACKSPACE)
170 {
171 if (offset > 0)
172 {
173 offset--;
174 if (buffer[offset] < 0 || buffer[offset] > 127) // UTF8
175 {
176 while (offset > 0 && (buffer[offset] & 0xc0) != 0xc0)
177 {
178 offset--;
179 }
180 display_len--;
181 prints("\033[D \033[D");
182 }
183 buffer[offset] = '\0';
184 display_len--;
185 prints("\033[D \033[D");
186 iflush();
187 }
188 continue;
189 }
190 else if (ch > 255 || iscntrl(ch))
191 {
192 continue;
193 }
194 else if ((ch & 0xff80) == 0x80) // head of multi-byte character
195 {
196 str_len = 0;
197 c = (char)(ch & 0xf0);
198 while (c & 0x80)
199 {
200 input_str[str_len] = (char)(ch - 256);
201 str_len++;
202 c = (c & 0x7f) << 1;
203
204 if ((c & 0x80) == 0) // Input completed
205 {
206 break;
207 }
208
209 // Expect additional bytes of input
210 ch = igetch(100); // 0.1 second
211 if (ch == KEY_NULL || ch == KEY_TIMEOUT) // Ignore received bytes if no futher input
212 {
213 #ifdef _DEBUG
214 log_error("Ignore %d bytes of incomplete UTF8 character\n", str_len);
215 #endif
216 str_len = 0;
217 break;
218 }
219 }
220 input_str[str_len] = '\0';
221
222 if (str_len == 0) // Incomplete input
223 {
224 continue;
225 }
226
227 if (mbstowcs(wcs, input_str, 1) == (size_t)-1)
228 {
229 log_error("mbstowcs() error\n");
230 }
231 if (offset + str_len > buf_size - 1 || display_len + (UTF8_fixed_width ? 2 : wcwidth(wcs[0])) > max_display_len) // No enough space for Chinese character
232 {
233 outc('\a');
234 iflush();
235 continue;
236 }
237
238 memcpy(buffer + offset, input_str, (size_t)str_len);
239 offset += str_len;
240 buffer[offset] = '\0';
241 display_len += 2;
242
243 switch (echo_mode)
244 {
245 case DOECHO:
246 prints(input_str);
247 break;
248 case NOECHO:
249 prints("**");
250 break;
251 }
252 }
253 else if (ch >= 32 && ch < 127) // Printable character
254 {
255 if (offset + 1 > buf_size - 1 || display_len + 1 > max_display_len)
256 {
257 outc('\a');
258 iflush();
259 continue;
260 }
261
262 buffer[offset++] = (char)ch;
263 buffer[offset] = '\0';
264 display_len++;
265
266 switch (echo_mode)
267 {
268 case DOECHO:
269 outc((char)ch);
270 break;
271 case NOECHO:
272 outc('*');
273 break;
274 }
275 }
276 else // Invalid character
277 {
278 continue;
279 }
280
281 iflush();
282 }
283
284 return offset;
285 }
286
287 int str_input(char *buffer, int buf_size, enum io_echo_t echo_mode)
288 {
289 int len;
290
291 buffer[0] = '\0';
292
293 len = _str_input(buffer, buf_size, buf_size, echo_mode);
294
295 prints("\r\n");
296 iflush();
297
298 return len;
299 }
300
301 int get_data(int row, int col, char *prompt, char *buffer, int buf_size, int max_display_len)
302 {
303 int len = 0;
304 int col_cur = 0;
305 int ch;
306 int offset = 0;
307 int eol;
308 int display_len;
309 char input_str[5];
310 int str_len = 0;
311 wchar_t wcs[2];
312 int wc_len;
313 char c;
314
315 buffer[buf_size - 1] = '\0';
316 offset = split_line(buffer, max_display_len, &eol, &display_len, 0);
317 buffer[offset] = '\0';
318 len = offset;
319 col_cur = col + str_length(prompt, 1) + display_len;
320
321 moveto(row, col);
322 prints("%s", prompt);
323 prints("%s", buffer);
324 prints("%*s", max_display_len - display_len, "");
325 moveto(row, col_cur);
326 iflush();
327
328 igetch_reset();
329
330 while (!SYS_server_exit)
331 {
332 ch = igetch_t(MIN(BBS_max_user_idle_time, 60));
333
334 if (ch == CR)
335 {
336 break;
337 }
338 else if (ch == KEY_TIMEOUT || ch == KEY_NULL) // timeout or broken pipe
339 {
340 return -1;
341 }
342 else if (ch == LF || ch == '\0')
343 {
344 continue;
345 }
346 else if (ch == BACKSPACE)
347 {
348 if (offset > 0)
349 {
350 str_len = 1;
351 offset--;
352 if (buffer[offset] < 0 || buffer[offset] > 127) // UTF8
353 {
354 while (offset > 0 && (buffer[offset] & 0xc0) != 0xc0)
355 {
356 str_len++;
357 offset--;
358 }
359
360 if (mbstowcs(wcs, buffer + offset, 1) == (size_t)-1)
361 {
362 log_error("mbstowcs() error\n");
363 }
364 wc_len = (UTF8_fixed_width ? 2 : wcwidth(wcs[0]));
365
366 if (wc_len == 2)
367 {
368 display_len--;
369 col_cur--;
370 }
371 }
372
373 memmove(buffer + offset, buffer + offset + str_len, (size_t)(len - offset - str_len));
374 len -= str_len;
375 buffer[len] = '\0';
376 display_len--;
377 col_cur--;
378
379 moveto(row, col_cur);
380 prints("%s", buffer + offset);
381 prints("%*s", max_display_len - display_len, "");
382 moveto(row, col_cur);
383 iflush();
384 }
385 continue;
386 }
387 else if (ch == KEY_DEL)
388 {
389 if (offset < len)
390 {
391 if ((buffer[offset] & 0x80) == 0x80) // head of multi-byte character
392 {
393 str_len = 0;
394 c = (char)(buffer[offset] & 0xf0);
395 while (c & 0x80)
396 {
397 str_len++;
398 c = (c & 0x7f) << 1;
399 }
400 display_len--;
401 }
402 else
403 {
404 str_len = 1;
405 }
406
407 memmove(buffer + offset, buffer + offset + str_len, (size_t)(len - offset - str_len));
408 len -= str_len;
409 buffer[len] = '\0';
410 display_len--;
411
412 moveto(row, col_cur);
413 prints("%s", buffer + offset);
414 prints("%*s", max_display_len - display_len, "");
415 moveto(row, col_cur);
416 iflush();
417 }
418 continue;
419 }
420 else if (ch == KEY_LEFT)
421 {
422 if (offset > 0)
423 {
424 str_len = 1;
425 offset--;
426 if (buffer[offset] < 0 || buffer[offset] > 127) // UTF8
427 {
428 while (offset > 0 && (buffer[offset] & 0xc0) != 0xc0)
429 {
430 str_len++;
431 offset--;
432 }
433
434 if (mbstowcs(wcs, buffer + offset, 1) == (size_t)-1)
435 {
436 log_error("mbstowcs() error\n");
437 }
438 wc_len = (UTF8_fixed_width ? 2 : wcwidth(wcs[0]));
439
440 if (wc_len == 2)
441 {
442 col_cur--;
443 }
444 }
445 col_cur--;
446
447 moveto(row, col_cur);
448 iflush();
449 }
450 continue;
451 }
452 else if (ch == KEY_RIGHT)
453 {
454 if (offset < len)
455 {
456 str_len = 0;
457 if ((buffer[offset] & 0x80) == 0x80) // head of multi-byte character
458 {
459 c = (char)(buffer[offset] & 0xf0);
460 while (c & 0x80)
461 {
462 str_len++;
463 c = (c & 0x7f) << 1;
464 }
465
466 if (mbstowcs(wcs, buffer + offset, 1) == (size_t)-1)
467 {
468 log_error("mbstowcs() error\n");
469 }
470 wc_len = (UTF8_fixed_width ? 2 : wcwidth(wcs[0]));
471
472 if (wc_len == 2)
473 {
474 col_cur++;
475 }
476 }
477 else
478 {
479 str_len = 1;
480 }
481
482 col_cur++;
483 offset += str_len;
484
485 moveto(row, col_cur);
486 iflush();
487 }
488 continue;
489 }
490 else if (ch == KEY_HOME || ch == KEY_UP)
491 {
492 if (offset > 0)
493 {
494 offset = 0;
495 col_cur = col + str_length(prompt, 1);
496
497 moveto(row, col_cur);
498 iflush();
499 }
500 continue;
501 }
502 else if (ch == KEY_END || ch == KEY_DOWN)
503 {
504 if (offset < len)
505 {
506 offset = len;
507 col_cur = col + str_length(prompt, 1) + display_len;
508
509 moveto(row, col_cur);
510 iflush();
511 }
512 continue;
513 }
514 else if (ch > 255 || iscntrl(ch))
515 {
516 continue;
517 }
518 else if ((ch & 0xff80) == 0x80) // head of multi-byte character
519 {
520 str_len = 0;
521 c = (char)(ch & 0xf0);
522 while (c & 0x80)
523 {
524 input_str[str_len] = (char)(ch - 256);
525 str_len++;
526 c = (c & 0x7f) << 1;
527
528 if ((c & 0x80) == 0) // Input completed
529 {
530 break;
531 }
532
533 // Expect additional bytes of input
534 ch = igetch(100); // 0.1 second
535 if (ch == KEY_NULL || ch == KEY_TIMEOUT) // Ignore received bytes if no futher input
536 {
537 #ifdef _DEBUG
538 log_error("Ignore %d bytes of incomplete UTF8 character\n", str_len);
539 #endif
540 str_len = 0;
541 break;
542 }
543 }
544 input_str[str_len] = '\0';
545
546 if (str_len == 0) // Incomplete input
547 {
548 continue;
549 }
550
551 if (mbstowcs(wcs, input_str, 1) == (size_t)-1)
552 {
553 log_error("mbstowcs() error\n");
554 }
555 wc_len = (UTF8_fixed_width ? 2 : wcwidth(wcs[0]));
556
557 if (len + str_len > buf_size - 1 ||
558 display_len + wc_len > max_display_len) // No enough space for Chinese character
559 {
560 outc('\a');
561 iflush();
562 continue;
563 }
564
565 memmove(buffer + offset + str_len, buffer + offset, (size_t)(len - offset));
566 memcpy(buffer + offset, input_str, (size_t)str_len);
567 len += str_len;
568 buffer[len] = '\0';
569 display_len += wc_len;
570
571 moveto(row, col_cur);
572 prints("%s", buffer + offset);
573 prints("%*s", max_display_len - display_len, "");
574
575 col_cur += wc_len;
576
577 moveto(row, col_cur);
578 iflush();
579
580 offset += str_len;
581 }
582 else if (ch >= 32 && ch < 127) // Printable character
583 {
584 if (len + 1 > buf_size - 1 || display_len + 1 > max_display_len)
585 {
586 outc('\a');
587 iflush();
588 continue;
589 }
590
591 memmove(buffer + offset + 1, buffer + offset, (size_t)(len - offset));
592 buffer[offset] = (char)ch;
593 len++;
594 buffer[len] = '\0';
595 display_len++;
596
597 moveto(row, col_cur);
598 prints("%s", buffer + offset);
599 prints("%*s", max_display_len - display_len, "");
600
601 col_cur++;
602
603 moveto(row, col_cur);
604 iflush();
605
606 offset++;
607 }
608 else // Invalid character
609 {
610 continue;
611 }
612 }
613
614 return len;
615 }
616
617 int display_data(const void *p_data, long display_line_total, const long *p_line_offsets, int eof_exit,
618 display_data_key_handler key_handler, const char *help_filename)
619 {
620 static int show_help = 1;
621 char buffer[LINE_BUFFER_LEN];
622 DISPLAY_CTX ctx;
623 int ch = 0;
624 int input_ok;
625 const int screen_begin_row = 1;
626 const int screen_row_total = SCREEN_ROWS - screen_begin_row;
627 int output_current_row = screen_begin_row;
628 int output_end_row = SCREEN_ROWS - 1;
629 long int line_current = 0;
630 long int len;
631 long int percentile;
632 int loop;
633 int eol, display_len;
634
635 clrline(output_current_row, SCREEN_ROWS);
636
637 // update msg_ext with extended key handler
638 if (key_handler(&ch, &ctx) != 0)
639 {
640 return ch;
641 }
642
643 loop = 1;
644 while (!SYS_server_exit && loop)
645 {
646 if (eof_exit > 0 && line_current >= display_line_total)
647 {
648 if (eof_exit == 1)
649 {
650 ch = press_any_key();
651 }
652 else // if (eof_exit == 2)
653 {
654 iflush();
655 }
656
657 loop = 0;
658 break;
659 }
660
661 if (line_current >= display_line_total || output_current_row > output_end_row)
662 {
663 ctx.reach_begin = (line_current < output_current_row ? 1 : 0);
664
665 if (line_current - (output_current_row - screen_begin_row) + screen_row_total < display_line_total)
666 {
667 percentile = (line_current - (output_current_row - screen_begin_row) + screen_row_total) * 100 / display_line_total;
668 ctx.reach_end = 0;
669 }
670 else
671 {
672 percentile = 100;
673 ctx.reach_end = 1;
674 }
675
676 ctx.line_top = line_current - (output_current_row - screen_begin_row) + 1;
677 ctx.line_bottom = MIN(line_current - (output_current_row - screen_begin_row) + screen_row_total, display_line_total);
678
679 snprintf(buffer, sizeof(buffer),
680 "\033[1;44;33m第\033[32m%ld\033[33m-\033[32m%ld\033[33m行 (\033[32m%ld%%\033[33m) %s",
681 ctx.line_top,
682 ctx.line_bottom,
683 percentile,
684 ctx.msg);
685
686 len = split_line(buffer, SCREEN_COLS, &eol, &display_len, 1);
687 for (; display_len < SCREEN_COLS; display_len++)
688 {
689 buffer[len++] = ' ';
690 }
691 buffer[len] = '\0';
692 strncat(buffer, "\033[m", sizeof(buffer) - 1 - strnlen(buffer, sizeof(buffer)));
693
694 moveto(SCREEN_ROWS, 0);
695 prints("%s", buffer);
696 iflush();
697
698 input_ok = 0;
699 while (!SYS_server_exit && !input_ok)
700 {
701 ch = igetch_t(BBS_max_user_idle_time);
702 input_ok = 1;
703
704 if (ch != KEY_NULL && ch != KEY_TIMEOUT)
705 {
706 BBS_last_access_tm = time(NULL);
707 }
708
709 // extended key handler
710 if (key_handler(&ch, &ctx) != 0)
711 {
712 goto cleanup;
713 }
714
715 switch (ch)
716 {
717 case KEY_NULL:
718 log_error("KEY_NULL\n");
719 goto cleanup;
720 case KEY_TIMEOUT:
721 log_error("User input timeout\n");
722 goto cleanup;
723 case KEY_HOME:
724 if (line_current - output_current_row < 0) // Reach begin
725 {
726 break;
727 }
728 line_current = 0;
729 output_current_row = screen_begin_row;
730 output_end_row = SCREEN_ROWS - 1;
731 clrline(output_current_row, SCREEN_ROWS);
732 break;
733 case KEY_END:
734 if (display_line_total < screen_row_total)
735 {
736 break;
737 }
738 line_current = display_line_total - screen_row_total;
739 output_current_row = screen_begin_row;
740 output_end_row = SCREEN_ROWS - 1;
741 clrline(output_current_row, SCREEN_ROWS);
742 break;
743 case KEY_UP:
744 if (line_current - output_current_row < 0) // Reach begin
745 {
746 break;
747 }
748 line_current -= output_current_row;
749 output_current_row = screen_begin_row;
750 // screen_end_line = screen_begin_line;
751 // prints("\033[T"); // Scroll down 1 line
752 output_end_row = SCREEN_ROWS - 1; // Legacy Fterm only works with this line
753 break;
754 case CR:
755 case KEY_DOWN:
756 if (line_current + (screen_row_total - (output_current_row - screen_begin_row)) >= display_line_total) // Reach end
757 {
758 break;
759 }
760 line_current += (screen_row_total - (output_current_row - screen_begin_row));
761 output_current_row = screen_row_total;
762 output_end_row = SCREEN_ROWS - 1;
763 moveto(SCREEN_ROWS, 0);
764 clrtoeol();
765 // prints("\033[S"); // Scroll up 1 line
766 prints("\n"); // Legacy Cterm only works with this line
767 break;
768 case KEY_PGUP:
769 if (line_current - output_current_row < 0) // Reach begin
770 {
771 break;
772 }
773 line_current -= ((screen_row_total - 1) + (output_current_row - screen_begin_row));
774 if (line_current < 0)
775 {
776 line_current = 0;
777 }
778 output_current_row = screen_begin_row;
779 output_end_row = SCREEN_ROWS - 1;
780 clrline(output_current_row, SCREEN_ROWS);
781 break;
782 case KEY_SPACE:
783 case KEY_PGDN:
784 if (line_current + screen_row_total - (output_current_row - screen_begin_row) >= display_line_total) // Reach end
785 {
786 break;
787 }
788 line_current += (screen_row_total - 1) - (output_current_row - screen_begin_row);
789 if (line_current + screen_row_total > display_line_total) // No enough lines to display
790 {
791 line_current = display_line_total - screen_row_total;
792 }
793 output_current_row = screen_begin_row;
794 output_end_row = SCREEN_ROWS - 1;
795 clrline(output_current_row, SCREEN_ROWS);
796 break;
797 case KEY_ESC:
798 case KEY_LEFT:
799 loop = 0;
800 break;
801 case 'h':
802 if (!show_help) // Not reentrant
803 {
804 break;
805 }
806 // Display help information
807 show_help = 0;
808 display_file(help_filename, 1);
809 show_help = 1;
810 case KEY_F5:
811 // Refresh after display help information
812 line_current -= (output_current_row - screen_begin_row);
813 output_current_row = screen_begin_row;
814 output_end_row = SCREEN_ROWS - 1;
815 clrline(output_current_row, SCREEN_ROWS);
816 break;
817 case 0: // Refresh bottom line
818 break;
819 default:
820 input_ok = 0;
821 break;
822 }
823 }
824
825 continue;
826 }
827
828 len = p_line_offsets[line_current + 1] - p_line_offsets[line_current];
829 if (len >= sizeof(buffer))
830 {
831 log_error("Buffer overflow: len=%ld(%ld - %ld) line=%ld \n",
832 len, p_line_offsets[line_current + 1], p_line_offsets[line_current], line_current);
833 len = sizeof(buffer) - 1;
834 }
835 else if (len < 0)
836 {
837 log_error("Incorrect line offsets: len=%ld(%ld - %ld) line=%ld \n",
838 len, p_line_offsets[line_current + 1], p_line_offsets[line_current], line_current);
839 len = 0;
840 }
841
842 memcpy(buffer, (const char *)p_data + p_line_offsets[line_current], (size_t)len);
843 buffer[len] = '\0';
844
845 moveto(output_current_row, 0);
846 clrtoeol();
847 prints("%s", buffer);
848 line_current++;
849 output_current_row++;
850 }
851
852 cleanup:
853 return ch;
854 }
855
856 int display_file_key_handler(int *p_key, DISPLAY_CTX *p_ctx)
857 {
858 switch (*p_key)
859 {
860 case 0: // Set msg
861 snprintf(p_ctx->msg, sizeof(p_ctx->msg),
862 "| 返回[\033[32m←\033[33m,\033[32mESC\033[33m] | "
863 "移动[\033[32m↑\033[33m/\033[32m↓\033[33m/\033[32mPgUp\033[33m/\033[32mPgDn\033[33m] | "
864 "帮助[\033[32mh\033[33m] |");
865 break;
866 }
867
868 return 0;
869 }
870
871 int display_file(const char *filename, int eof_exit)
872 {
873 int ret;
874 const void *p_shm;
875 size_t data_len;
876 long line_total;
877 const void *p_data;
878 const long *p_line_offsets;
879
880 if ((p_shm = get_file_shm_readonly(filename, &data_len, &line_total, &p_data, &p_line_offsets)) == NULL)
881 {
882 log_error("get_file_shm(%s) error\n", filename);
883 return KEY_NULL;
884 }
885
886 if (user_online_update("VIEW_FILE") < 0)
887 {
888 log_error("user_online_update(VIEW_FILE) error\n");
889 }
890
891 ret = display_data(p_data, line_total, p_line_offsets, eof_exit, display_file_key_handler, DATA_READ_HELP);
892
893 if (detach_file_shm(p_shm) < 0)
894 {
895 log_error("detach_file_shm(%s) error\n", filename);
896 }
897
898 return ret;
899 }
900
901 int show_top(const char *str_left, const char *str_middle, const char *str_right)
902 {
903 char str_left_f[STR_TOP_LEFT_MAX_LEN + 1];
904 char str_middle_f[STR_TOP_MIDDLE_MAX_LEN + 1];
905 char str_right_f[STR_TOP_RIGHT_MAX_LEN + 1];
906 int str_left_len;
907 int str_middle_len;
908 int str_right_len;
909 int eol;
910 int len;
911
912 strncpy(str_left_f, str_left, sizeof(str_left_f) - 1);
913 str_left_f[sizeof(str_left_f) - 1] = '\0';
914 len = split_line(str_left_f, STR_TOP_LEFT_MAX_LEN / 2, &eol, &str_left_len, 1);
915 str_left_f[len] = '\0';
916
917 strncpy(str_middle_f, str_middle, sizeof(str_middle_f) - 1);
918 str_middle_f[sizeof(str_middle_f) - 1] = '\0';
919 len = split_line(str_middle, STR_TOP_MIDDLE_MAX_LEN / 2, &eol, &str_middle_len, 1);
920 str_middle_f[len] = '\0';
921
922 strncpy(str_right_f, str_right, sizeof(str_right_f) - 1);
923 str_right_f[sizeof(str_right_f) - 1] = '\0';
924 len = split_line(str_right, STR_TOP_RIGHT_MAX_LEN / 2, &eol, &str_right_len, 1);
925 str_right_f[len] = '\0';
926
927 moveto(1, 0);
928 clrtoeol();
929 prints("\033[1;44;33m%s\033[37m%*s%s\033[33m%*s%s\033[m",
930 str_left_f, 44 - str_left_len - str_middle_len, "",
931 str_middle_f, 36 - str_right_len, "", str_right_f);
932
933 return 0;
934 }
935
936 int show_bottom(const char *msg)
937 {
938 char str_time[LINE_BUFFER_LEN];
939 int len_str_time;
940 time_t time_online;
941 struct tm *tm_online;
942 char msg_f[LINE_BUFFER_LEN];
943 int eol;
944 int len_msg;
945 int len;
946 int len_username;
947 char str_tm_online[LINE_BUFFER_LEN];
948 int len_str_tm_online;
949
950 len_str_time = (int)get_time_str(str_time, sizeof(str_time));
951
952 msg_f[0] = '\0';
953 len_msg = 0;
954 if (msg != NULL)
955 {
956 strncpy(msg_f, msg, sizeof(msg_f) - 1);
957 msg_f[sizeof(msg_f) - 1] = '\0';
958 len = split_line(msg_f, 23, &eol, &len_msg, 1);
959 msg_f[len] = '\0';
960 }
961
962 len_username = (int)strnlen(BBS_username, sizeof(BBS_username));
963
964 time_online = time(NULL) - BBS_login_tm;
965 tm_online = gmtime(&time_online);
966 if (tm_online->tm_mday > 1)
967 {
968 snprintf(str_tm_online, sizeof(str_tm_online),
969 "\033[36m%d\033[33md \033[36m%d\033[33m:\033[36m%.2d",
970 tm_online->tm_mday - 1, tm_online->tm_hour, tm_online->tm_min);
971 }
972 else
973 {
974 snprintf(str_tm_online, sizeof(str_tm_online),
975 "\033[36m%d\033[33m:\033[36m%.2d",
976 tm_online->tm_hour, tm_online->tm_min);
977 }
978 len_str_tm_online = str_length(str_tm_online, 1);
979
980 moveto(SCREEN_ROWS, 0);
981 clrtoeol();
982 prints("\033[1;44;33m时间[\033[36m%s\033[33m]%s%*s \033[33m用户[\033[36m%s\033[33m][%s\033[33m]\033[m",
983 str_time, msg_f, 65 - len_str_time - len_msg - len_username - len_str_tm_online,
984 "", BBS_username, str_tm_online);
985
986 return 0;
987 }
988
989 int show_active_board()
990 {
991 static int line_current = 0;
992 static const void *p_shm = NULL;
993 static size_t data_len;
994 static long line_total;
995 static const void *p_data;
996 static const long *p_line_offsets;
997
998 static time_t t_last_show = 0;
999 static int line_last = 0;
1000
1001 char buffer[LINE_BUFFER_LEN];
1002 long int len;
1003
1004 if (p_shm == NULL)
1005 {
1006 if ((p_shm = get_file_shm_readonly(DATA_ACTIVE_BOARD, &data_len, &line_total, &p_data, &p_line_offsets)) == NULL)
1007 {
1008 log_error("get_file_shm(%s) error\n", DATA_ACTIVE_BOARD);
1009 return KEY_NULL;
1010 }
1011 }
1012
1013 if (time(NULL) - t_last_show >= 10)
1014 {
1015 line_last = line_current;
1016 t_last_show = time(NULL);
1017 }
1018 else
1019 {
1020 line_current = line_last;
1021 }
1022
1023 clrline(2, 2 + ACTIVE_BOARD_HEIGHT);
1024
1025 for (int i = 0; i < ACTIVE_BOARD_HEIGHT; i++)
1026 {
1027 len = p_line_offsets[line_current + 1] - p_line_offsets[line_current];
1028 if (len >= LINE_BUFFER_LEN)
1029 {
1030 log_error("buffer overflow: len=%ld(%ld - %ld) line=%ld \n",
1031 len, p_line_offsets[line_current + 1], p_line_offsets[line_current], line_current);
1032 len = LINE_BUFFER_LEN - 1;
1033 }
1034
1035 memcpy(buffer, (const char *)p_data + p_line_offsets[line_current], (size_t)len);
1036 buffer[len] = '\0';
1037
1038 moveto(3 + i, 0);
1039 prints("%s", buffer);
1040
1041 line_current++;
1042 if (line_current >= line_total)
1043 {
1044 line_current = 0;
1045 break;
1046 }
1047 }
1048
1049 return 0;
1050 }

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