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

Contents of /lbbs/src/screen.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.112 - (show annotations)
Fri Oct 17 10:57:43 2025 UTC (4 months, 4 weeks ago) by sysadm
Branch: MAIN
Changes since 1.111: +12 -1 lines
Content type: text/x-csrc
Ignore empty input in press_any_key()

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

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